summaryrefslogtreecommitdiffstats
path: root/src/cmd/compile/internal/gc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 13:14:23 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 13:14:23 +0000
commit73df946d56c74384511a194dd01dbe099584fd1a (patch)
treefd0bcea490dd81327ddfbb31e215439672c9a068 /src/cmd/compile/internal/gc
parentInitial commit. (diff)
downloadgolang-1.16-upstream.tar.xz
golang-1.16-upstream.zip
Adding upstream version 1.16.10.upstream/1.16.10upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cmd/compile/internal/gc')
-rw-r--r--src/cmd/compile/internal/gc/alg.go959
-rw-r--r--src/cmd/compile/internal/gc/algkind_string.go48
-rw-r--r--src/cmd/compile/internal/gc/align.go531
-rw-r--r--src/cmd/compile/internal/gc/bench_test.go64
-rw-r--r--src/cmd/compile/internal/gc/bexport.go177
-rw-r--r--src/cmd/compile/internal/gc/bimport.go24
-rw-r--r--src/cmd/compile/internal/gc/bitset.go59
-rw-r--r--src/cmd/compile/internal/gc/bootstrap.go13
-rw-r--r--src/cmd/compile/internal/gc/builtin.go340
-rw-r--r--src/cmd/compile/internal/gc/builtin/runtime.go259
-rw-r--r--src/cmd/compile/internal/gc/builtin_test.go32
-rw-r--r--src/cmd/compile/internal/gc/bv.go278
-rw-r--r--src/cmd/compile/internal/gc/class_string.go29
-rw-r--r--src/cmd/compile/internal/gc/closure.go594
-rw-r--r--src/cmd/compile/internal/gc/const.go1323
-rw-r--r--src/cmd/compile/internal/gc/constFold_test.go18111
-rw-r--r--src/cmd/compile/internal/gc/dcl.go1185
-rw-r--r--src/cmd/compile/internal/gc/dep_test.go25
-rw-r--r--src/cmd/compile/internal/gc/dump.go280
-rw-r--r--src/cmd/compile/internal/gc/dwinl.go450
-rw-r--r--src/cmd/compile/internal/gc/embed.go256
-rw-r--r--src/cmd/compile/internal/gc/esc.go472
-rw-r--r--src/cmd/compile/internal/gc/escape.go1539
-rw-r--r--src/cmd/compile/internal/gc/export.go233
-rw-r--r--src/cmd/compile/internal/gc/fixedbugs_test.go92
-rw-r--r--src/cmd/compile/internal/gc/float_test.go544
-rw-r--r--src/cmd/compile/internal/gc/fmt.go1986
-rw-r--r--src/cmd/compile/internal/gc/gen.go86
-rw-r--r--src/cmd/compile/internal/gc/global_test.go116
-rw-r--r--src/cmd/compile/internal/gc/go.go349
-rw-r--r--src/cmd/compile/internal/gc/gsubr.go333
-rw-r--r--src/cmd/compile/internal/gc/iexport.go1515
-rw-r--r--src/cmd/compile/internal/gc/iface_test.go128
-rw-r--r--src/cmd/compile/internal/gc/iimport.go1117
-rw-r--r--src/cmd/compile/internal/gc/init.go109
-rw-r--r--src/cmd/compile/internal/gc/initorder.go358
-rw-r--r--src/cmd/compile/internal/gc/inl.go1507
-rw-r--r--src/cmd/compile/internal/gc/inl_test.go269
-rw-r--r--src/cmd/compile/internal/gc/lang_test.go64
-rw-r--r--src/cmd/compile/internal/gc/lex.go224
-rw-r--r--src/cmd/compile/internal/gc/lex_test.go121
-rw-r--r--src/cmd/compile/internal/gc/logic_test.go289
-rw-r--r--src/cmd/compile/internal/gc/main.go1610
-rw-r--r--src/cmd/compile/internal/gc/mapfile_mmap.go48
-rw-r--r--src/cmd/compile/internal/gc/mapfile_read.go21
-rw-r--r--src/cmd/compile/internal/gc/mkbuiltin.go225
-rw-r--r--src/cmd/compile/internal/gc/mpfloat.go357
-rw-r--r--src/cmd/compile/internal/gc/mpint.go304
-rw-r--r--src/cmd/compile/internal/gc/noder.go1756
-rw-r--r--src/cmd/compile/internal/gc/obj.go639
-rw-r--r--src/cmd/compile/internal/gc/op_string.go175
-rw-r--r--src/cmd/compile/internal/gc/order.go1441
-rw-r--r--src/cmd/compile/internal/gc/pgen.go798
-rw-r--r--src/cmd/compile/internal/gc/pgen_test.go196
-rw-r--r--src/cmd/compile/internal/gc/phi.go538
-rw-r--r--src/cmd/compile/internal/gc/plive.go1321
-rw-r--r--src/cmd/compile/internal/gc/pprof.go13
-rw-r--r--src/cmd/compile/internal/gc/racewalk.go93
-rw-r--r--src/cmd/compile/internal/gc/range.go628
-rw-r--r--src/cmd/compile/internal/gc/reflect.go1901
-rw-r--r--src/cmd/compile/internal/gc/reproduciblebuilds_test.go112
-rw-r--r--src/cmd/compile/internal/gc/scc.go140
-rw-r--r--src/cmd/compile/internal/gc/scope.go109
-rw-r--r--src/cmd/compile/internal/gc/scope_test.go538
-rw-r--r--src/cmd/compile/internal/gc/select.go387
-rw-r--r--src/cmd/compile/internal/gc/shift_test.go1031
-rw-r--r--src/cmd/compile/internal/gc/sinit.go1172
-rw-r--r--src/cmd/compile/internal/gc/sizeof_test.go39
-rw-r--r--src/cmd/compile/internal/gc/ssa.go7231
-rw-r--r--src/cmd/compile/internal/gc/ssa_test.go191
-rw-r--r--src/cmd/compile/internal/gc/subr.go1918
-rw-r--r--src/cmd/compile/internal/gc/swt.go756
-rw-r--r--src/cmd/compile/internal/gc/syntax.go1196
-rw-r--r--src/cmd/compile/internal/gc/testdata/addressed_test.go210
-rw-r--r--src/cmd/compile/internal/gc/testdata/append_test.go61
-rw-r--r--src/cmd/compile/internal/gc/testdata/arithBoundary_test.go694
-rw-r--r--src/cmd/compile/internal/gc/testdata/arithConst_test.go9570
-rw-r--r--src/cmd/compile/internal/gc/testdata/arith_test.go1454
-rw-r--r--src/cmd/compile/internal/gc/testdata/array_test.go132
-rw-r--r--src/cmd/compile/internal/gc/testdata/assert_test.go128
-rw-r--r--src/cmd/compile/internal/gc/testdata/break_test.go250
-rw-r--r--src/cmd/compile/internal/gc/testdata/chan_test.go63
-rw-r--r--src/cmd/compile/internal/gc/testdata/closure_test.go32
-rw-r--r--src/cmd/compile/internal/gc/testdata/cmpConst_test.go2209
-rw-r--r--src/cmd/compile/internal/gc/testdata/cmp_test.go37
-rw-r--r--src/cmd/compile/internal/gc/testdata/compound_test.go128
-rw-r--r--src/cmd/compile/internal/gc/testdata/copy_test.go760
-rw-r--r--src/cmd/compile/internal/gc/testdata/ctl_test.go149
-rw-r--r--src/cmd/compile/internal/gc/testdata/deferNoReturn_test.go21
-rw-r--r--src/cmd/compile/internal/gc/testdata/divbyzero_test.go48
-rw-r--r--src/cmd/compile/internal/gc/testdata/dupLoad_test.go83
-rw-r--r--src/cmd/compile/internal/gc/testdata/flowgraph_generator1.go315
-rw-r--r--src/cmd/compile/internal/gc/testdata/fp_test.go1773
-rw-r--r--src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go209
-rw-r--r--src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go346
-rw-r--r--src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go247
-rw-r--r--src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go307
-rw-r--r--src/cmd/compile/internal/gc/testdata/gen/copyGen.go121
-rw-r--r--src/cmd/compile/internal/gc/testdata/gen/zeroGen.go143
-rw-r--r--src/cmd/compile/internal/gc/testdata/loadstore_test.go204
-rw-r--r--src/cmd/compile/internal/gc/testdata/map_test.go37
-rw-r--r--src/cmd/compile/internal/gc/testdata/namedReturn_test.go93
-rw-r--r--src/cmd/compile/internal/gc/testdata/phi_test.go99
-rw-r--r--src/cmd/compile/internal/gc/testdata/regalloc_test.go50
-rw-r--r--src/cmd/compile/internal/gc/testdata/reproducible/issue20272.go34
-rw-r--r--src/cmd/compile/internal/gc/testdata/reproducible/issue27013.go15
-rw-r--r--src/cmd/compile/internal/gc/testdata/reproducible/issue30202.go17
-rw-r--r--src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go70
-rw-r--r--src/cmd/compile/internal/gc/testdata/short_test.go57
-rw-r--r--src/cmd/compile/internal/gc/testdata/slice_test.go46
-rw-r--r--src/cmd/compile/internal/gc/testdata/sqrtConst_test.go50
-rw-r--r--src/cmd/compile/internal/gc/testdata/string_test.go207
-rw-r--r--src/cmd/compile/internal/gc/testdata/unsafe_test.go145
-rw-r--r--src/cmd/compile/internal/gc/testdata/zero_test.go711
-rw-r--r--src/cmd/compile/internal/gc/timings.go235
-rw-r--r--src/cmd/compile/internal/gc/trace.go27
-rw-r--r--src/cmd/compile/internal/gc/truncconst_test.go63
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go4019
-rw-r--r--src/cmd/compile/internal/gc/types.go58
-rw-r--r--src/cmd/compile/internal/gc/types_acc.go16
-rw-r--r--src/cmd/compile/internal/gc/universe.go453
-rw-r--r--src/cmd/compile/internal/gc/unsafe.go76
-rw-r--r--src/cmd/compile/internal/gc/util.go103
-rw-r--r--src/cmd/compile/internal/gc/walk.go4125
-rw-r--r--src/cmd/compile/internal/gc/zerorange_test.go98
125 files changed, 93970 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
new file mode 100644
index 0000000..2f7fa27
--- /dev/null
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -0,0 +1,959 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "fmt"
+ "sort"
+)
+
+// AlgKind describes the kind of algorithms used for comparing and
+// hashing a Type.
+type AlgKind int
+
+//go:generate stringer -type AlgKind -trimprefix A
+
+const (
+ // These values are known by runtime.
+ ANOEQ AlgKind = iota
+ AMEM0
+ AMEM8
+ AMEM16
+ AMEM32
+ AMEM64
+ AMEM128
+ ASTRING
+ AINTER
+ ANILINTER
+ AFLOAT32
+ AFLOAT64
+ ACPLX64
+ ACPLX128
+
+ // Type can be compared/hashed as regular memory.
+ AMEM AlgKind = 100
+
+ // Type needs special comparison/hashing functions.
+ ASPECIAL AlgKind = -1
+)
+
+// IsComparable reports whether t is a comparable type.
+func IsComparable(t *types.Type) bool {
+ a, _ := algtype1(t)
+ return a != ANOEQ
+}
+
+// IsRegularMemory reports whether t can be compared/hashed as regular memory.
+func IsRegularMemory(t *types.Type) bool {
+ a, _ := algtype1(t)
+ return a == AMEM
+}
+
+// IncomparableField returns an incomparable Field of struct Type t, if any.
+func IncomparableField(t *types.Type) *types.Field {
+ for _, f := range t.FieldSlice() {
+ if !IsComparable(f.Type) {
+ return f
+ }
+ }
+ return nil
+}
+
+// EqCanPanic reports whether == on type t could panic (has an interface somewhere).
+// t must be comparable.
+func EqCanPanic(t *types.Type) bool {
+ switch t.Etype {
+ default:
+ return false
+ case TINTER:
+ return true
+ case TARRAY:
+ return EqCanPanic(t.Elem())
+ case TSTRUCT:
+ for _, f := range t.FieldSlice() {
+ if !f.Sym.IsBlank() && EqCanPanic(f.Type) {
+ return true
+ }
+ }
+ return false
+ }
+}
+
+// algtype is like algtype1, except it returns the fixed-width AMEMxx variants
+// instead of the general AMEM kind when possible.
+func algtype(t *types.Type) AlgKind {
+ a, _ := algtype1(t)
+ if a == AMEM {
+ switch t.Width {
+ case 0:
+ return AMEM0
+ case 1:
+ return AMEM8
+ case 2:
+ return AMEM16
+ case 4:
+ return AMEM32
+ case 8:
+ return AMEM64
+ case 16:
+ return AMEM128
+ }
+ }
+
+ return a
+}
+
+// algtype1 returns the AlgKind used for comparing and hashing Type t.
+// If it returns ANOEQ, it also returns the component type of t that
+// makes it incomparable.
+func algtype1(t *types.Type) (AlgKind, *types.Type) {
+ if t.Broke() {
+ return AMEM, nil
+ }
+ if t.Noalg() {
+ return ANOEQ, t
+ }
+
+ switch t.Etype {
+ case TANY, TFORW:
+ // will be defined later.
+ return ANOEQ, t
+
+ case TINT8, TUINT8, TINT16, TUINT16,
+ TINT32, TUINT32, TINT64, TUINT64,
+ TINT, TUINT, TUINTPTR,
+ TBOOL, TPTR,
+ TCHAN, TUNSAFEPTR:
+ return AMEM, nil
+
+ case TFUNC, TMAP:
+ return ANOEQ, t
+
+ case TFLOAT32:
+ return AFLOAT32, nil
+
+ case TFLOAT64:
+ return AFLOAT64, nil
+
+ case TCOMPLEX64:
+ return ACPLX64, nil
+
+ case TCOMPLEX128:
+ return ACPLX128, nil
+
+ case TSTRING:
+ return ASTRING, nil
+
+ case TINTER:
+ if t.IsEmptyInterface() {
+ return ANILINTER, nil
+ }
+ return AINTER, nil
+
+ case TSLICE:
+ return ANOEQ, t
+
+ case TARRAY:
+ a, bad := algtype1(t.Elem())
+ switch a {
+ case AMEM:
+ return AMEM, nil
+ case ANOEQ:
+ return ANOEQ, bad
+ }
+
+ switch t.NumElem() {
+ case 0:
+ // We checked above that the element type is comparable.
+ return AMEM, nil
+ case 1:
+ // Single-element array is same as its lone element.
+ return a, nil
+ }
+
+ return ASPECIAL, nil
+
+ case TSTRUCT:
+ fields := t.FieldSlice()
+
+ // One-field struct is same as that one field alone.
+ if len(fields) == 1 && !fields[0].Sym.IsBlank() {
+ return algtype1(fields[0].Type)
+ }
+
+ ret := AMEM
+ for i, f := range fields {
+ // All fields must be comparable.
+ a, bad := algtype1(f.Type)
+ if a == ANOEQ {
+ return ANOEQ, bad
+ }
+
+ // Blank fields, padded fields, fields with non-memory
+ // equality need special compare.
+ if a != AMEM || f.Sym.IsBlank() || ispaddedfield(t, i) {
+ ret = ASPECIAL
+ }
+ }
+
+ return ret, nil
+ }
+
+ Fatalf("algtype1: unexpected type %v", t)
+ return 0, nil
+}
+
+// genhash returns a symbol which is the closure used to compute
+// the hash of a value of type t.
+// Note: the generated function must match runtime.typehash exactly.
+func genhash(t *types.Type) *obj.LSym {
+ switch algtype(t) {
+ default:
+ // genhash is only called for types that have equality
+ Fatalf("genhash %v", t)
+ case AMEM0:
+ return sysClosure("memhash0")
+ case AMEM8:
+ return sysClosure("memhash8")
+ case AMEM16:
+ return sysClosure("memhash16")
+ case AMEM32:
+ return sysClosure("memhash32")
+ case AMEM64:
+ return sysClosure("memhash64")
+ case AMEM128:
+ return sysClosure("memhash128")
+ case ASTRING:
+ return sysClosure("strhash")
+ case AINTER:
+ return sysClosure("interhash")
+ case ANILINTER:
+ return sysClosure("nilinterhash")
+ case AFLOAT32:
+ return sysClosure("f32hash")
+ case AFLOAT64:
+ return sysClosure("f64hash")
+ case ACPLX64:
+ return sysClosure("c64hash")
+ case ACPLX128:
+ return sysClosure("c128hash")
+ case AMEM:
+ // For other sizes of plain memory, we build a closure
+ // that calls memhash_varlen. The size of the memory is
+ // encoded in the first slot of the closure.
+ closure := typeLookup(fmt.Sprintf(".hashfunc%d", t.Width)).Linksym()
+ if len(closure.P) > 0 { // already generated
+ return closure
+ }
+ if memhashvarlen == nil {
+ memhashvarlen = sysfunc("memhash_varlen")
+ }
+ ot := 0
+ ot = dsymptr(closure, ot, memhashvarlen, 0)
+ ot = duintptr(closure, ot, uint64(t.Width)) // size encoded in closure
+ ggloblsym(closure, int32(ot), obj.DUPOK|obj.RODATA)
+ return closure
+ case ASPECIAL:
+ break
+ }
+
+ closure := typesymprefix(".hashfunc", t).Linksym()
+ if len(closure.P) > 0 { // already generated
+ return closure
+ }
+
+ // Generate hash functions for subtypes.
+ // There are cases where we might not use these hashes,
+ // but in that case they will get dead-code eliminated.
+ // (And the closure generated by genhash will also get
+ // dead-code eliminated, as we call the subtype hashers
+ // directly.)
+ switch t.Etype {
+ case types.TARRAY:
+ genhash(t.Elem())
+ case types.TSTRUCT:
+ for _, f := range t.FieldSlice() {
+ genhash(f.Type)
+ }
+ }
+
+ sym := typesymprefix(".hash", t)
+ if Debug.r != 0 {
+ fmt.Printf("genhash %v %v %v\n", closure, sym, t)
+ }
+
+ lineno = autogeneratedPos // less confusing than end of input
+ dclcontext = PEXTERN
+
+ // func sym(p *T, h uintptr) uintptr
+ tfn := nod(OTFUNC, nil, nil)
+ tfn.List.Set2(
+ namedfield("p", types.NewPtr(t)),
+ namedfield("h", types.Types[TUINTPTR]),
+ )
+ tfn.Rlist.Set1(anonfield(types.Types[TUINTPTR]))
+
+ fn := dclfunc(sym, tfn)
+ np := asNode(tfn.Type.Params().Field(0).Nname)
+ nh := asNode(tfn.Type.Params().Field(1).Nname)
+
+ switch t.Etype {
+ case types.TARRAY:
+ // An array of pure memory would be handled by the
+ // standard algorithm, so the element type must not be
+ // pure memory.
+ hashel := hashfor(t.Elem())
+
+ n := nod(ORANGE, nil, nod(ODEREF, np, nil))
+ ni := newname(lookup("i"))
+ ni.Type = types.Types[TINT]
+ n.List.Set1(ni)
+ n.SetColas(true)
+ colasdefn(n.List.Slice(), n)
+ ni = n.List.First()
+
+ // h = hashel(&p[i], h)
+ call := nod(OCALL, hashel, nil)
+
+ nx := nod(OINDEX, np, ni)
+ nx.SetBounded(true)
+ na := nod(OADDR, nx, nil)
+ call.List.Append(na)
+ call.List.Append(nh)
+ n.Nbody.Append(nod(OAS, nh, call))
+
+ fn.Nbody.Append(n)
+
+ case types.TSTRUCT:
+ // Walk the struct using memhash for runs of AMEM
+ // and calling specific hash functions for the others.
+ for i, fields := 0, t.FieldSlice(); i < len(fields); {
+ f := fields[i]
+
+ // Skip blank fields.
+ if f.Sym.IsBlank() {
+ i++
+ continue
+ }
+
+ // Hash non-memory fields with appropriate hash function.
+ if !IsRegularMemory(f.Type) {
+ 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.List.Append(na)
+ call.List.Append(nh)
+ fn.Nbody.Append(nod(OAS, nh, call))
+ i++
+ continue
+ }
+
+ // Otherwise, hash a maximal length run of raw memory.
+ size, next := memrun(t, i)
+
+ // h = hashel(&p.first, size, h)
+ hashel := hashmem(f.Type)
+ call := nod(OCALL, hashel, nil)
+ nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
+ na := nod(OADDR, nx, nil)
+ call.List.Append(na)
+ call.List.Append(nh)
+ call.List.Append(nodintconst(size))
+ fn.Nbody.Append(nod(OAS, nh, call))
+
+ i = next
+ }
+ }
+
+ r := nod(ORETURN, nil, nil)
+ r.List.Append(nh)
+ fn.Nbody.Append(r)
+
+ if Debug.r != 0 {
+ dumplist("genhash body", fn.Nbody)
+ }
+
+ funcbody()
+
+ fn.Func.SetDupok(true)
+ fn = typecheck(fn, ctxStmt)
+
+ Curfn = fn
+ typecheckslice(fn.Nbody.Slice(), ctxStmt)
+ Curfn = nil
+
+ if debug_dclstack != 0 {
+ testdclstack()
+ }
+
+ fn.Func.SetNilCheckDisabled(true)
+ xtop = append(xtop, fn)
+
+ // Build closure. It doesn't close over any variables, so
+ // it contains just the function pointer.
+ dsymptr(closure, 0, sym.Linksym(), 0)
+ ggloblsym(closure, int32(Widthptr), obj.DUPOK|obj.RODATA)
+
+ return closure
+}
+
+func hashfor(t *types.Type) *Node {
+ var sym *types.Sym
+
+ switch a, _ := algtype1(t); a {
+ case AMEM:
+ Fatalf("hashfor with AMEM type")
+ case AINTER:
+ sym = Runtimepkg.Lookup("interhash")
+ case ANILINTER:
+ sym = Runtimepkg.Lookup("nilinterhash")
+ case ASTRING:
+ sym = Runtimepkg.Lookup("strhash")
+ case AFLOAT32:
+ sym = Runtimepkg.Lookup("f32hash")
+ case AFLOAT64:
+ sym = Runtimepkg.Lookup("f64hash")
+ case ACPLX64:
+ sym = Runtimepkg.Lookup("c64hash")
+ case ACPLX128:
+ sym = Runtimepkg.Lookup("c128hash")
+ default:
+ // Note: the caller of hashfor ensured that this symbol
+ // exists and has a body by calling genhash for t.
+ sym = typesymprefix(".hash", t)
+ }
+
+ n := newname(sym)
+ setNodeNameFunc(n)
+ n.Type = functype(nil, []*Node{
+ anonfield(types.NewPtr(t)),
+ anonfield(types.Types[TUINTPTR]),
+ }, []*Node{
+ anonfield(types.Types[TUINTPTR]),
+ })
+ return n
+}
+
+// sysClosure returns a closure which will call the
+// given runtime function (with no closed-over variables).
+func sysClosure(name string) *obj.LSym {
+ s := sysvar(name + "·f")
+ if len(s.P) == 0 {
+ f := sysfunc(name)
+ dsymptr(s, 0, f, 0)
+ ggloblsym(s, int32(Widthptr), obj.DUPOK|obj.RODATA)
+ }
+ return s
+}
+
+// geneq returns a symbol which is the closure used to compute
+// equality for two objects of type t.
+func geneq(t *types.Type) *obj.LSym {
+ switch algtype(t) {
+ case ANOEQ:
+ // The runtime will panic if it tries to compare
+ // a type with a nil equality function.
+ return nil
+ case AMEM0:
+ return sysClosure("memequal0")
+ case AMEM8:
+ return sysClosure("memequal8")
+ case AMEM16:
+ return sysClosure("memequal16")
+ case AMEM32:
+ return sysClosure("memequal32")
+ case AMEM64:
+ return sysClosure("memequal64")
+ case AMEM128:
+ return sysClosure("memequal128")
+ case ASTRING:
+ return sysClosure("strequal")
+ case AINTER:
+ return sysClosure("interequal")
+ case ANILINTER:
+ return sysClosure("nilinterequal")
+ case AFLOAT32:
+ return sysClosure("f32equal")
+ case AFLOAT64:
+ return sysClosure("f64equal")
+ case ACPLX64:
+ return sysClosure("c64equal")
+ case ACPLX128:
+ return sysClosure("c128equal")
+ case AMEM:
+ // make equality closure. The size of the type
+ // is encoded in the closure.
+ closure := typeLookup(fmt.Sprintf(".eqfunc%d", t.Width)).Linksym()
+ if len(closure.P) != 0 {
+ return closure
+ }
+ if memequalvarlen == nil {
+ memequalvarlen = sysvar("memequal_varlen") // asm func
+ }
+ ot := 0
+ ot = dsymptr(closure, ot, memequalvarlen, 0)
+ ot = duintptr(closure, ot, uint64(t.Width))
+ ggloblsym(closure, int32(ot), obj.DUPOK|obj.RODATA)
+ return closure
+ case ASPECIAL:
+ break
+ }
+
+ closure := typesymprefix(".eqfunc", t).Linksym()
+ if len(closure.P) > 0 { // already generated
+ return closure
+ }
+ sym := typesymprefix(".eq", t)
+ if Debug.r != 0 {
+ fmt.Printf("geneq %v\n", t)
+ }
+
+ // Autogenerate code for equality of structs and arrays.
+
+ lineno = autogeneratedPos // less confusing than end of input
+ dclcontext = PEXTERN
+
+ // func sym(p, q *T) bool
+ tfn := nod(OTFUNC, nil, nil)
+ tfn.List.Set2(
+ namedfield("p", types.NewPtr(t)),
+ namedfield("q", types.NewPtr(t)),
+ )
+ tfn.Rlist.Set1(namedfield("r", types.Types[TBOOL]))
+
+ fn := dclfunc(sym, tfn)
+ np := asNode(tfn.Type.Params().Field(0).Nname)
+ nq := asNode(tfn.Type.Params().Field(1).Nname)
+ nr := asNode(tfn.Type.Results().Field(0).Nname)
+
+ // Label to jump to if an equality test fails.
+ neq := autolabel(".neq")
+
+ // We reach here only for types that have equality but
+ // cannot be handled by the standard algorithms,
+ // so t must be either an array or a struct.
+ switch t.Etype {
+ default:
+ Fatalf("geneq %v", t)
+
+ case TARRAY:
+ nelem := t.NumElem()
+
+ // checkAll generates code to check the equality of all array elements.
+ // If unroll is greater than nelem, checkAll generates:
+ //
+ // if eq(p[0], q[0]) && eq(p[1], q[1]) && ... {
+ // } else {
+ // return
+ // }
+ //
+ // And so on.
+ //
+ // Otherwise it generates:
+ //
+ // for i := 0; i < nelem; i++ {
+ // if eq(p[i], q[i]) {
+ // } else {
+ // goto neq
+ // }
+ // }
+ //
+ // TODO(josharian): consider doing some loop unrolling
+ // for larger nelem as well, processing a few elements at a time in a loop.
+ checkAll := func(unroll int64, last bool, eq func(pi, qi *Node) *Node) {
+ // checkIdx generates a node to check for equality at index i.
+ checkIdx := func(i *Node) *Node {
+ // pi := p[i]
+ pi := nod(OINDEX, np, i)
+ pi.SetBounded(true)
+ pi.Type = t.Elem()
+ // qi := q[i]
+ qi := nod(OINDEX, nq, i)
+ qi.SetBounded(true)
+ qi.Type = t.Elem()
+ return eq(pi, qi)
+ }
+
+ if nelem <= unroll {
+ if last {
+ // Do last comparison in a different manner.
+ nelem--
+ }
+ // Generate a series of checks.
+ for i := int64(0); i < nelem; i++ {
+ // if check {} else { goto neq }
+ nif := nod(OIF, checkIdx(nodintconst(i)), nil)
+ nif.Rlist.Append(nodSym(OGOTO, nil, neq))
+ fn.Nbody.Append(nif)
+ }
+ if last {
+ fn.Nbody.Append(nod(OAS, nr, checkIdx(nodintconst(nelem))))
+ }
+ } else {
+ // Generate a for loop.
+ // for i := 0; i < nelem; i++
+ i := temp(types.Types[TINT])
+ init := nod(OAS, i, nodintconst(0))
+ cond := nod(OLT, i, nodintconst(nelem))
+ post := nod(OAS, i, nod(OADD, i, nodintconst(1)))
+ loop := nod(OFOR, cond, post)
+ loop.Ninit.Append(init)
+ // if eq(pi, qi) {} else { goto neq }
+ nif := nod(OIF, checkIdx(i), nil)
+ nif.Rlist.Append(nodSym(OGOTO, nil, neq))
+ loop.Nbody.Append(nif)
+ fn.Nbody.Append(loop)
+ if last {
+ fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
+ }
+ }
+ }
+
+ switch t.Elem().Etype {
+ case TSTRING:
+ // Do two loops. First, check that all the lengths match (cheap).
+ // Second, check that all the contents match (expensive).
+ // TODO: when the array size is small, unroll the length match checks.
+ checkAll(3, false, func(pi, qi *Node) *Node {
+ // Compare lengths.
+ eqlen, _ := eqstring(pi, qi)
+ return eqlen
+ })
+ checkAll(1, true, func(pi, qi *Node) *Node {
+ // Compare contents.
+ _, eqmem := eqstring(pi, qi)
+ return eqmem
+ })
+ case TFLOAT32, TFLOAT64:
+ checkAll(2, true, func(pi, qi *Node) *Node {
+ // p[i] == q[i]
+ return nod(OEQ, pi, qi)
+ })
+ // TODO: pick apart structs, do them piecemeal too
+ default:
+ checkAll(1, true, func(pi, qi *Node) *Node {
+ // p[i] == q[i]
+ return nod(OEQ, pi, qi)
+ })
+ }
+
+ case TSTRUCT:
+ // Build a list of conditions to satisfy.
+ // The conditions are a list-of-lists. Conditions are reorderable
+ // within each inner list. The outer lists must be evaluated in order.
+ var conds [][]*Node
+ conds = append(conds, []*Node{})
+ and := func(n *Node) {
+ i := len(conds) - 1
+ conds[i] = append(conds[i], n)
+ }
+
+ // Walk the struct using memequal for runs of AMEM
+ // and calling specific equality tests for the others.
+ for i, fields := 0, t.FieldSlice(); i < len(fields); {
+ f := fields[i]
+
+ // Skip blank-named fields.
+ if f.Sym.IsBlank() {
+ i++
+ continue
+ }
+
+ // Compare non-memory fields with field equality.
+ if !IsRegularMemory(f.Type) {
+ if EqCanPanic(f.Type) {
+ // Enforce ordering by starting a new set of reorderable conditions.
+ conds = append(conds, []*Node{})
+ }
+ p := nodSym(OXDOT, np, f.Sym)
+ q := nodSym(OXDOT, nq, f.Sym)
+ switch {
+ case f.Type.IsString():
+ eqlen, eqmem := eqstring(p, q)
+ and(eqlen)
+ and(eqmem)
+ default:
+ and(nod(OEQ, p, q))
+ }
+ if EqCanPanic(f.Type) {
+ // Also enforce ordering after something that can panic.
+ conds = append(conds, []*Node{})
+ }
+ i++
+ continue
+ }
+
+ // Find maximal length run of memory-only fields.
+ size, next := memrun(t, i)
+
+ // TODO(rsc): All the calls to newname are wrong for
+ // cross-package unexported fields.
+ if s := fields[i:next]; len(s) <= 2 {
+ // Two or fewer fields: use plain field equality.
+ for _, f := range s {
+ and(eqfield(np, nq, f.Sym))
+ }
+ } else {
+ // More than two fields: use memequal.
+ and(eqmem(np, nq, f.Sym, size))
+ }
+ i = next
+ }
+
+ // Sort conditions to put runtime calls last.
+ // Preserve the rest of the ordering.
+ var flatConds []*Node
+ for _, c := range conds {
+ isCall := func(n *Node) bool {
+ return n.Op == OCALL || n.Op == OCALLFUNC
+ }
+ sort.SliceStable(c, func(i, j int) bool {
+ return !isCall(c[i]) && isCall(c[j])
+ })
+ flatConds = append(flatConds, c...)
+ }
+
+ if len(flatConds) == 0 {
+ fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
+ } else {
+ for _, c := range flatConds[:len(flatConds)-1] {
+ // if cond {} else { goto neq }
+ n := nod(OIF, c, nil)
+ n.Rlist.Append(nodSym(OGOTO, nil, neq))
+ fn.Nbody.Append(n)
+ }
+ fn.Nbody.Append(nod(OAS, nr, flatConds[len(flatConds)-1]))
+ }
+ }
+
+ // ret:
+ // return
+ ret := autolabel(".ret")
+ fn.Nbody.Append(nodSym(OLABEL, nil, ret))
+ fn.Nbody.Append(nod(ORETURN, nil, nil))
+
+ // neq:
+ // r = false
+ // return (or goto ret)
+ fn.Nbody.Append(nodSym(OLABEL, nil, neq))
+ fn.Nbody.Append(nod(OAS, nr, nodbool(false)))
+ if EqCanPanic(t) || hasCall(fn) {
+ // Epilogue is large, so share it with the equal case.
+ fn.Nbody.Append(nodSym(OGOTO, nil, ret))
+ } else {
+ // Epilogue is small, so don't bother sharing.
+ fn.Nbody.Append(nod(ORETURN, nil, nil))
+ }
+ // TODO(khr): the epilogue size detection condition above isn't perfect.
+ // We should really do a generic CL that shares epilogues across
+ // the board. See #24936.
+
+ if Debug.r != 0 {
+ dumplist("geneq body", fn.Nbody)
+ }
+
+ funcbody()
+
+ fn.Func.SetDupok(true)
+ fn = typecheck(fn, ctxStmt)
+
+ Curfn = fn
+ typecheckslice(fn.Nbody.Slice(), ctxStmt)
+ Curfn = nil
+
+ if debug_dclstack != 0 {
+ testdclstack()
+ }
+
+ // Disable checknils while compiling this code.
+ // We are comparing a struct or an array,
+ // neither of which can be nil, and our comparisons
+ // are shallow.
+ fn.Func.SetNilCheckDisabled(true)
+ xtop = append(xtop, fn)
+
+ // Generate a closure which points at the function we just generated.
+ dsymptr(closure, 0, sym.Linksym(), 0)
+ ggloblsym(closure, int32(Widthptr), obj.DUPOK|obj.RODATA)
+ return closure
+}
+
+func hasCall(n *Node) bool {
+ if n.Op == OCALL || n.Op == OCALLFUNC {
+ return true
+ }
+ if n.Left != nil && hasCall(n.Left) {
+ return true
+ }
+ if n.Right != nil && hasCall(n.Right) {
+ return true
+ }
+ for _, x := range n.Ninit.Slice() {
+ if hasCall(x) {
+ return true
+ }
+ }
+ for _, x := range n.Nbody.Slice() {
+ if hasCall(x) {
+ return true
+ }
+ }
+ for _, x := range n.List.Slice() {
+ if hasCall(x) {
+ return true
+ }
+ }
+ for _, x := range n.Rlist.Slice() {
+ if hasCall(x) {
+ return true
+ }
+ }
+ return false
+}
+
+// eqfield returns the node
+// p.field == q.field
+func eqfield(p *Node, q *Node, field *types.Sym) *Node {
+ nx := nodSym(OXDOT, p, field)
+ ny := nodSym(OXDOT, q, field)
+ ne := nod(OEQ, nx, ny)
+ return ne
+}
+
+// eqstring returns the nodes
+// len(s) == len(t)
+// and
+// memequal(s.ptr, t.ptr, len(s))
+// which can be used to construct string equality comparison.
+// eqlen must be evaluated before eqmem, and shortcircuiting is required.
+func eqstring(s, t *Node) (eqlen, eqmem *Node) {
+ s = conv(s, types.Types[TSTRING])
+ t = conv(t, types.Types[TSTRING])
+ sptr := nod(OSPTR, s, nil)
+ tptr := nod(OSPTR, t, nil)
+ slen := conv(nod(OLEN, s, nil), types.Types[TUINTPTR])
+ tlen := conv(nod(OLEN, t, nil), types.Types[TUINTPTR])
+
+ fn := syslook("memequal")
+ fn = substArgTypes(fn, types.Types[TUINT8], types.Types[TUINT8])
+ call := nod(OCALL, fn, nil)
+ call.List.Append(sptr, tptr, slen.copy())
+ call = typecheck(call, ctxExpr|ctxMultiOK)
+
+ cmp := nod(OEQ, slen, tlen)
+ cmp = typecheck(cmp, ctxExpr)
+ cmp.Type = types.Types[TBOOL]
+ return cmp, call
+}
+
+// eqinterface returns the nodes
+// s.tab == t.tab (or s.typ == t.typ, as appropriate)
+// and
+// ifaceeq(s.tab, s.data, t.data) (or efaceeq(s.typ, s.data, t.data), as appropriate)
+// which can be used to construct interface equality comparison.
+// eqtab must be evaluated before eqdata, and shortcircuiting is required.
+func eqinterface(s, t *Node) (eqtab, eqdata *Node) {
+ if !types.Identical(s.Type, t.Type) {
+ Fatalf("eqinterface %v %v", s.Type, t.Type)
+ }
+ // func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
+ // func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
+ var fn *Node
+ if s.Type.IsEmptyInterface() {
+ fn = syslook("efaceeq")
+ } else {
+ fn = syslook("ifaceeq")
+ }
+
+ stab := nod(OITAB, s, nil)
+ ttab := nod(OITAB, t, nil)
+ sdata := nod(OIDATA, s, nil)
+ tdata := nod(OIDATA, t, nil)
+ sdata.Type = types.Types[TUNSAFEPTR]
+ tdata.Type = types.Types[TUNSAFEPTR]
+ sdata.SetTypecheck(1)
+ tdata.SetTypecheck(1)
+
+ call := nod(OCALL, fn, nil)
+ call.List.Append(stab, sdata, tdata)
+ call = typecheck(call, ctxExpr|ctxMultiOK)
+
+ cmp := nod(OEQ, stab, ttab)
+ cmp = typecheck(cmp, ctxExpr)
+ cmp.Type = types.Types[TBOOL]
+ return cmp, call
+}
+
+// eqmem returns the node
+// memequal(&p.field, &q.field [, size])
+func eqmem(p *Node, q *Node, field *types.Sym, size int64) *Node {
+ nx := nod(OADDR, nodSym(OXDOT, p, field), nil)
+ ny := nod(OADDR, nodSym(OXDOT, q, field), nil)
+ nx = typecheck(nx, ctxExpr)
+ ny = typecheck(ny, ctxExpr)
+
+ fn, needsize := eqmemfunc(size, nx.Type.Elem())
+ call := nod(OCALL, fn, nil)
+ call.List.Append(nx)
+ call.List.Append(ny)
+ if needsize {
+ call.List.Append(nodintconst(size))
+ }
+
+ return call
+}
+
+func eqmemfunc(size int64, t *types.Type) (fn *Node, needsize bool) {
+ switch size {
+ default:
+ fn = syslook("memequal")
+ needsize = true
+ case 1, 2, 4, 8, 16:
+ buf := fmt.Sprintf("memequal%d", int(size)*8)
+ fn = syslook(buf)
+ }
+
+ fn = substArgTypes(fn, t, t)
+ return fn, needsize
+}
+
+// memrun finds runs of struct fields for which memory-only algs are appropriate.
+// t is the parent struct type, and start is the field index at which to start the run.
+// size is the length in bytes of the memory included in the run.
+// next is the index just after the end of the memory run.
+func memrun(t *types.Type, start int) (size int64, next int) {
+ next = start
+ for {
+ next++
+ if next == t.NumFields() {
+ break
+ }
+ // Stop run after a padded field.
+ if ispaddedfield(t, next-1) {
+ break
+ }
+ // Also, stop before a blank or non-memory field.
+ if f := t.Field(next); f.Sym.IsBlank() || !IsRegularMemory(f.Type) {
+ break
+ }
+ }
+ return t.Field(next-1).End() - t.Field(start).Offset, next
+}
+
+// ispaddedfield reports whether the i'th field of struct type t is followed
+// by padding.
+func ispaddedfield(t *types.Type, i int) bool {
+ if !t.IsStruct() {
+ Fatalf("ispaddedfield called non-struct %v", t)
+ }
+ end := t.Width
+ if i+1 < t.NumFields() {
+ end = t.Field(i + 1).Offset
+ }
+ return t.Field(i).End() != end
+}
diff --git a/src/cmd/compile/internal/gc/algkind_string.go b/src/cmd/compile/internal/gc/algkind_string.go
new file mode 100644
index 0000000..52b5399
--- /dev/null
+++ b/src/cmd/compile/internal/gc/algkind_string.go
@@ -0,0 +1,48 @@
+// Code generated by "stringer -type AlgKind -trimprefix A"; DO NOT EDIT.
+
+package gc
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[ANOEQ-0]
+ _ = x[AMEM0-1]
+ _ = x[AMEM8-2]
+ _ = x[AMEM16-3]
+ _ = x[AMEM32-4]
+ _ = x[AMEM64-5]
+ _ = x[AMEM128-6]
+ _ = x[ASTRING-7]
+ _ = x[AINTER-8]
+ _ = x[ANILINTER-9]
+ _ = x[AFLOAT32-10]
+ _ = x[AFLOAT64-11]
+ _ = x[ACPLX64-12]
+ _ = x[ACPLX128-13]
+ _ = x[AMEM-100]
+ _ = x[ASPECIAL - -1]
+}
+
+const (
+ _AlgKind_name_0 = "SPECIALNOEQMEM0MEM8MEM16MEM32MEM64MEM128STRINGINTERNILINTERFLOAT32FLOAT64CPLX64CPLX128"
+ _AlgKind_name_1 = "MEM"
+)
+
+var (
+ _AlgKind_index_0 = [...]uint8{0, 7, 11, 15, 19, 24, 29, 34, 40, 46, 51, 59, 66, 73, 79, 86}
+)
+
+func (i AlgKind) String() string {
+ switch {
+ case -1 <= i && i <= 13:
+ i -= -1
+ return _AlgKind_name_0[_AlgKind_index_0[i]:_AlgKind_index_0[i+1]]
+ case i == 100:
+ return _AlgKind_name_1
+ default:
+ return "AlgKind(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
new file mode 100644
index 0000000..a3a0c8f
--- /dev/null
+++ b/src/cmd/compile/internal/gc/align.go
@@ -0,0 +1,531 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "bytes"
+ "cmd/compile/internal/types"
+ "fmt"
+ "sort"
+)
+
+// sizeCalculationDisabled indicates whether it is safe
+// to calculate Types' widths and alignments. See dowidth.
+var sizeCalculationDisabled bool
+
+// machine size and rounding alignment is dictated around
+// the size of a pointer, set in betypeinit (see ../amd64/galign.go).
+var defercalc int
+
+func Rnd(o int64, r int64) int64 {
+ if r < 1 || r > 8 || r&(r-1) != 0 {
+ Fatalf("rnd %d", r)
+ }
+ return (o + r - 1) &^ (r - 1)
+}
+
+// expandiface computes the method set for interface type t by
+// expanding embedded interfaces.
+func expandiface(t *types.Type) {
+ seen := make(map[*types.Sym]*types.Field)
+ var methods []*types.Field
+
+ addMethod := func(m *types.Field, explicit bool) {
+ switch prev := seen[m.Sym]; {
+ case prev == nil:
+ seen[m.Sym] = m
+ case langSupported(1, 14, t.Pkg()) && !explicit && types.Identical(m.Type, prev.Type):
+ return
+ default:
+ yyerrorl(m.Pos, "duplicate method %s", m.Sym.Name)
+ }
+ methods = append(methods, m)
+ }
+
+ for _, m := range t.Methods().Slice() {
+ if m.Sym == nil {
+ continue
+ }
+
+ checkwidth(m.Type)
+ addMethod(m, true)
+ }
+
+ for _, m := range t.Methods().Slice() {
+ if m.Sym != nil {
+ continue
+ }
+
+ if !m.Type.IsInterface() {
+ yyerrorl(m.Pos, "interface contains embedded non-interface %v", m.Type)
+ m.SetBroke(true)
+ t.SetBroke(true)
+ // Add to fields so that error messages
+ // include the broken embedded type when
+ // printing t.
+ // TODO(mdempsky): Revisit this.
+ methods = append(methods, m)
+ continue
+ }
+
+ // Embedded interface: duplicate all methods
+ // (including broken ones, if any) and add to t's
+ // method set.
+ for _, t1 := range m.Type.Fields().Slice() {
+ f := types.NewField()
+ f.Pos = m.Pos // preserve embedding position
+ f.Sym = t1.Sym
+ f.Type = t1.Type
+ f.SetBroke(t1.Broke())
+ addMethod(f, false)
+ }
+ }
+
+ sort.Sort(methcmp(methods))
+
+ if int64(len(methods)) >= thearch.MAXWIDTH/int64(Widthptr) {
+ yyerrorl(typePos(t), "interface too large")
+ }
+ for i, m := range methods {
+ m.Offset = int64(i) * int64(Widthptr)
+ }
+
+ // Access fields directly to avoid recursively calling dowidth
+ // within Type.Fields().
+ t.Extra.(*types.Interface).Fields.Set(methods)
+}
+
+func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 {
+ starto := o
+ maxalign := int32(flag)
+ if maxalign < 1 {
+ maxalign = 1
+ }
+ lastzero := int64(0)
+ for _, f := range t.Fields().Slice() {
+ if f.Type == nil {
+ // broken field, just skip it so that other valid fields
+ // get a width.
+ continue
+ }
+
+ dowidth(f.Type)
+ if int32(f.Type.Align) > maxalign {
+ maxalign = int32(f.Type.Align)
+ }
+ if f.Type.Align > 0 {
+ o = Rnd(o, int64(f.Type.Align))
+ }
+ f.Offset = o
+ if n := asNode(f.Nname); n != nil {
+ // addrescapes has similar code to update these offsets.
+ // Usually addrescapes runs after widstruct,
+ // in which case we could drop this,
+ // but function closure functions are the exception.
+ // NOTE(rsc): This comment may be stale.
+ // It's possible the ordering has changed and this is
+ // now the common case. I'm not sure.
+ if n.Name.Param.Stackcopy != nil {
+ n.Name.Param.Stackcopy.Xoffset = o
+ n.Xoffset = 0
+ } else {
+ n.Xoffset = o
+ }
+ }
+
+ w := f.Type.Width
+ if w < 0 {
+ Fatalf("invalid width %d", f.Type.Width)
+ }
+ if w == 0 {
+ lastzero = o
+ }
+ o += w
+ maxwidth := thearch.MAXWIDTH
+ // On 32-bit systems, reflect tables impose an additional constraint
+ // that each field start offset must fit in 31 bits.
+ if maxwidth < 1<<32 {
+ maxwidth = 1<<31 - 1
+ }
+ if o >= maxwidth {
+ yyerrorl(typePos(errtype), "type %L too large", errtype)
+ o = 8 // small but nonzero
+ }
+ }
+
+ // For nonzero-sized structs which end in a zero-sized thing, we add
+ // an extra byte of padding to the type. This padding ensures that
+ // taking the address of the zero-sized thing can't manufacture a
+ // pointer to the next object in the heap. See issue 9401.
+ if flag == 1 && o > starto && o == lastzero {
+ o++
+ }
+
+ // final width is rounded
+ if flag != 0 {
+ o = Rnd(o, int64(maxalign))
+ }
+ t.Align = uint8(maxalign)
+
+ // type width only includes back to first field's offset
+ t.Width = o - starto
+
+ return o
+}
+
+// findTypeLoop searches for an invalid type declaration loop involving
+// type t and reports whether one is found. If so, path contains the
+// loop.
+//
+// path points to a slice used for tracking the sequence of types
+// visited. Using a pointer to a slice allows the slice capacity to
+// grow and limit reallocations.
+func findTypeLoop(t *types.Type, path *[]*types.Type) bool {
+ // We implement a simple DFS loop-finding algorithm. This
+ // could be faster, but type cycles are rare.
+
+ if t.Sym != nil {
+ // Declared type. Check for loops and otherwise
+ // recurse on the type expression used in the type
+ // declaration.
+
+ for i, x := range *path {
+ if x == t {
+ *path = (*path)[i:]
+ return true
+ }
+ }
+
+ *path = append(*path, t)
+ if p := asNode(t.Nod).Name.Param; p != nil && findTypeLoop(p.Ntype.Type, path) {
+ return true
+ }
+ *path = (*path)[:len(*path)-1]
+ } else {
+ // Anonymous type. Recurse on contained types.
+
+ switch t.Etype {
+ case TARRAY:
+ if findTypeLoop(t.Elem(), path) {
+ return true
+ }
+ case TSTRUCT:
+ for _, f := range t.Fields().Slice() {
+ if findTypeLoop(f.Type, path) {
+ return true
+ }
+ }
+ case TINTER:
+ for _, m := range t.Methods().Slice() {
+ if m.Type.IsInterface() { // embedded interface
+ if findTypeLoop(m.Type, path) {
+ return true
+ }
+ }
+ }
+ }
+ }
+
+ return false
+}
+
+func reportTypeLoop(t *types.Type) {
+ if t.Broke() {
+ return
+ }
+
+ var l []*types.Type
+ if !findTypeLoop(t, &l) {
+ Fatalf("failed to find type loop for: %v", t)
+ }
+
+ // Rotate loop so that the earliest type declaration is first.
+ i := 0
+ for j, t := range l[1:] {
+ if typePos(t).Before(typePos(l[i])) {
+ i = j + 1
+ }
+ }
+ l = append(l[i:], l[:i]...)
+
+ var msg bytes.Buffer
+ fmt.Fprintf(&msg, "invalid recursive type %v\n", l[0])
+ for _, t := range l {
+ fmt.Fprintf(&msg, "\t%v: %v refers to\n", linestr(typePos(t)), t)
+ t.SetBroke(true)
+ }
+ fmt.Fprintf(&msg, "\t%v: %v", linestr(typePos(l[0])), l[0])
+ yyerrorl(typePos(l[0]), msg.String())
+}
+
+// dowidth calculates and stores the size and alignment for t.
+// If sizeCalculationDisabled is set, and the size/alignment
+// have not already been calculated, it calls Fatal.
+// This is used to prevent data races in the back end.
+func dowidth(t *types.Type) {
+ // Calling dowidth when typecheck tracing enabled is not safe.
+ // See issue #33658.
+ if enableTrace && skipDowidthForTracing {
+ return
+ }
+ if Widthptr == 0 {
+ Fatalf("dowidth without betypeinit")
+ }
+
+ if t == nil {
+ return
+ }
+
+ if t.Width == -2 {
+ reportTypeLoop(t)
+ t.Width = 0
+ t.Align = 1
+ return
+ }
+
+ if t.WidthCalculated() {
+ return
+ }
+
+ if sizeCalculationDisabled {
+ if t.Broke() {
+ // break infinite recursion from Fatal call below
+ return
+ }
+ t.SetBroke(true)
+ Fatalf("width not calculated: %v", t)
+ }
+
+ // break infinite recursion if the broken recursive type
+ // is referenced again
+ if t.Broke() && t.Width == 0 {
+ return
+ }
+
+ // defer checkwidth calls until after we're done
+ defercheckwidth()
+
+ lno := lineno
+ if asNode(t.Nod) != nil {
+ lineno = asNode(t.Nod).Pos
+ }
+
+ t.Width = -2
+ t.Align = 0 // 0 means use t.Width, below
+
+ et := t.Etype
+ switch et {
+ case TFUNC, TCHAN, TMAP, TSTRING:
+ break
+
+ // simtype == 0 during bootstrap
+ default:
+ if simtype[t.Etype] != 0 {
+ et = simtype[t.Etype]
+ }
+ }
+
+ var w int64
+ switch et {
+ default:
+ Fatalf("dowidth: unknown type: %v", t)
+
+ // compiler-specific stuff
+ case TINT8, TUINT8, TBOOL:
+ // bool is int8
+ w = 1
+
+ case TINT16, TUINT16:
+ w = 2
+
+ case TINT32, TUINT32, TFLOAT32:
+ w = 4
+
+ case TINT64, TUINT64, TFLOAT64:
+ w = 8
+ t.Align = uint8(Widthreg)
+
+ case TCOMPLEX64:
+ w = 8
+ t.Align = 4
+
+ case TCOMPLEX128:
+ w = 16
+ t.Align = uint8(Widthreg)
+
+ case TPTR:
+ w = int64(Widthptr)
+ checkwidth(t.Elem())
+
+ case TUNSAFEPTR:
+ w = int64(Widthptr)
+
+ case TINTER: // implemented as 2 pointers
+ w = 2 * int64(Widthptr)
+ t.Align = uint8(Widthptr)
+ expandiface(t)
+
+ case TCHAN: // implemented as pointer
+ w = int64(Widthptr)
+
+ checkwidth(t.Elem())
+
+ // make fake type to check later to
+ // trigger channel argument check.
+ t1 := types.NewChanArgs(t)
+ checkwidth(t1)
+
+ case TCHANARGS:
+ t1 := t.ChanArgs()
+ dowidth(t1) // just in case
+ if t1.Elem().Width >= 1<<16 {
+ yyerrorl(typePos(t1), "channel element type too large (>64kB)")
+ }
+ w = 1 // anything will do
+
+ case TMAP: // implemented as pointer
+ w = int64(Widthptr)
+ checkwidth(t.Elem())
+ checkwidth(t.Key())
+
+ case TFORW: // should have been filled in
+ reportTypeLoop(t)
+ w = 1 // anything will do
+
+ case TANY:
+ // dummy type; should be replaced before use.
+ Fatalf("dowidth any")
+
+ case TSTRING:
+ if sizeofString == 0 {
+ Fatalf("early dowidth string")
+ }
+ w = sizeofString
+ t.Align = uint8(Widthptr)
+
+ case TARRAY:
+ if t.Elem() == nil {
+ break
+ }
+
+ dowidth(t.Elem())
+ if t.Elem().Width != 0 {
+ cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
+ if uint64(t.NumElem()) > cap {
+ yyerrorl(typePos(t), "type %L larger than address space", t)
+ }
+ }
+ w = t.NumElem() * t.Elem().Width
+ t.Align = t.Elem().Align
+
+ case TSLICE:
+ if t.Elem() == nil {
+ break
+ }
+ w = sizeofSlice
+ checkwidth(t.Elem())
+ t.Align = uint8(Widthptr)
+
+ case TSTRUCT:
+ if t.IsFuncArgStruct() {
+ Fatalf("dowidth fn struct %v", t)
+ }
+ w = widstruct(t, t, 0, 1)
+
+ // make fake type to check later to
+ // trigger function argument computation.
+ case TFUNC:
+ t1 := types.NewFuncArgs(t)
+ checkwidth(t1)
+ w = int64(Widthptr) // width of func type is pointer
+
+ // function is 3 cated structures;
+ // compute their widths as side-effect.
+ case TFUNCARGS:
+ t1 := t.FuncArgs()
+ w = widstruct(t1, t1.Recvs(), 0, 0)
+ w = widstruct(t1, t1.Params(), w, Widthreg)
+ w = widstruct(t1, t1.Results(), w, Widthreg)
+ t1.Extra.(*types.Func).Argwid = w
+ if w%int64(Widthreg) != 0 {
+ Warn("bad type %v %d\n", t1, w)
+ }
+ t.Align = 1
+ }
+
+ if Widthptr == 4 && w != int64(int32(w)) {
+ yyerrorl(typePos(t), "type %v too large", t)
+ }
+
+ t.Width = w
+ if t.Align == 0 {
+ if w == 0 || w > 8 || w&(w-1) != 0 {
+ Fatalf("invalid alignment for %v", t)
+ }
+ t.Align = uint8(w)
+ }
+
+ lineno = lno
+
+ resumecheckwidth()
+}
+
+// when a type's width should be known, we call checkwidth
+// to compute it. during a declaration like
+//
+// type T *struct { next T }
+//
+// it is necessary to defer the calculation of the struct width
+// until after T has been initialized to be a pointer to that struct.
+// similarly, during import processing structs may be used
+// before their definition. in those situations, calling
+// defercheckwidth() stops width calculations until
+// resumecheckwidth() is called, at which point all the
+// checkwidths that were deferred are executed.
+// dowidth should only be called when the type's size
+// is needed immediately. checkwidth makes sure the
+// size is evaluated eventually.
+
+var deferredTypeStack []*types.Type
+
+func checkwidth(t *types.Type) {
+ if t == nil {
+ return
+ }
+
+ // function arg structs should not be checked
+ // outside of the enclosing function.
+ if t.IsFuncArgStruct() {
+ Fatalf("checkwidth %v", t)
+ }
+
+ if defercalc == 0 {
+ dowidth(t)
+ return
+ }
+
+ // if type has not yet been pushed on deferredTypeStack yet, do it now
+ if !t.Deferwidth() {
+ t.SetDeferwidth(true)
+ deferredTypeStack = append(deferredTypeStack, t)
+ }
+}
+
+func defercheckwidth() {
+ defercalc++
+}
+
+func resumecheckwidth() {
+ if defercalc == 1 {
+ for len(deferredTypeStack) > 0 {
+ t := deferredTypeStack[len(deferredTypeStack)-1]
+ deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
+ t.SetDeferwidth(false)
+ dowidth(t)
+ }
+ }
+
+ defercalc--
+}
diff --git a/src/cmd/compile/internal/gc/bench_test.go b/src/cmd/compile/internal/gc/bench_test.go
new file mode 100644
index 0000000..8c42881
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bench_test.go
@@ -0,0 +1,64 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import "testing"
+
+var globl int64
+var globl32 int32
+
+func BenchmarkLoadAdd(b *testing.B) {
+ x := make([]int64, 1024)
+ y := make([]int64, 1024)
+ for i := 0; i < b.N; i++ {
+ var s int64
+ for i := range x {
+ s ^= x[i] + y[i]
+ }
+ globl = s
+ }
+}
+
+// Added for ppc64 extswsli on power9
+func BenchmarkExtShift(b *testing.B) {
+ x := make([]int32, 1024)
+ for i := 0; i < b.N; i++ {
+ var s int64
+ for i := range x {
+ s ^= int64(x[i]+32) * 8
+ }
+ globl = s
+ }
+}
+
+func BenchmarkModify(b *testing.B) {
+ a := make([]int64, 1024)
+ v := globl
+ for i := 0; i < b.N; i++ {
+ for j := range a {
+ a[j] += v
+ }
+ }
+}
+
+func BenchmarkMullImm(b *testing.B) {
+ x := make([]int32, 1024)
+ for i := 0; i < b.N; i++ {
+ var s int32
+ for i := range x {
+ s += x[i] * 100
+ }
+ globl32 = s
+ }
+}
+
+func BenchmarkConstModify(b *testing.B) {
+ a := make([]int64, 1024)
+ for i := 0; i < b.N; i++ {
+ for j := range a {
+ a[j] += 3
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
new file mode 100644
index 0000000..10f21f8
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -0,0 +1,177 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+)
+
+type exporter struct {
+ marked map[*types.Type]bool // types already seen by markType
+}
+
+// markType recursively visits types reachable from t to identify
+// functions whose inline bodies may be needed.
+func (p *exporter) markType(t *types.Type) {
+ if p.marked[t] {
+ return
+ }
+ p.marked[t] = true
+
+ // If this is a named type, mark all of its associated
+ // methods. Skip interface types because t.Methods contains
+ // only their unexpanded method set (i.e., exclusive of
+ // interface embeddings), and the switch statement below
+ // handles their full method set.
+ if t.Sym != nil && t.Etype != TINTER {
+ for _, m := range t.Methods().Slice() {
+ if types.IsExported(m.Sym.Name) {
+ p.markType(m.Type)
+ }
+ }
+ }
+
+ // Recursively mark any types that can be produced given a
+ // value of type t: dereferencing a pointer; indexing or
+ // iterating over an array, slice, or map; receiving from a
+ // channel; accessing a struct field or interface method; or
+ // calling a function.
+ //
+ // Notably, we don't mark function parameter types, because
+ // the user already needs some way to construct values of
+ // those types.
+ switch t.Etype {
+ case TPTR, TARRAY, TSLICE:
+ p.markType(t.Elem())
+
+ case TCHAN:
+ if t.ChanDir().CanRecv() {
+ p.markType(t.Elem())
+ }
+
+ case TMAP:
+ p.markType(t.Key())
+ p.markType(t.Elem())
+
+ case TSTRUCT:
+ for _, f := range t.FieldSlice() {
+ if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
+ p.markType(f.Type)
+ }
+ }
+
+ case TFUNC:
+ // If t is the type of a function or method, then
+ // t.Nname() is its ONAME. Mark its inline body and
+ // any recursively called functions for export.
+ inlFlood(asNode(t.Nname()))
+
+ for _, f := range t.Results().FieldSlice() {
+ p.markType(f.Type)
+ }
+
+ case TINTER:
+ for _, f := range t.FieldSlice() {
+ if types.IsExported(f.Sym.Name) {
+ p.markType(f.Type)
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Export format
+
+// Tags. Must be < 0.
+const (
+ // Objects
+ packageTag = -(iota + 1)
+ constTag
+ typeTag
+ varTag
+ funcTag
+ endTag
+
+ // Types
+ namedTag
+ arrayTag
+ sliceTag
+ dddTag
+ structTag
+ pointerTag
+ signatureTag
+ interfaceTag
+ mapTag
+ chanTag
+
+ // Values
+ falseTag
+ trueTag
+ int64Tag
+ floatTag
+ fractionTag // not used by gc
+ complexTag
+ stringTag
+ nilTag
+ unknownTag // not used by gc (only appears in packages with errors)
+
+ // Type aliases
+ aliasTag
+)
+
+var predecl []*types.Type // initialized lazily
+
+func predeclared() []*types.Type {
+ if predecl == nil {
+ // initialize lazily to be sure that all
+ // elements have been initialized before
+ predecl = []*types.Type{
+ // basic types
+ types.Types[TBOOL],
+ types.Types[TINT],
+ types.Types[TINT8],
+ types.Types[TINT16],
+ types.Types[TINT32],
+ types.Types[TINT64],
+ types.Types[TUINT],
+ types.Types[TUINT8],
+ types.Types[TUINT16],
+ types.Types[TUINT32],
+ types.Types[TUINT64],
+ types.Types[TUINTPTR],
+ types.Types[TFLOAT32],
+ types.Types[TFLOAT64],
+ types.Types[TCOMPLEX64],
+ types.Types[TCOMPLEX128],
+ types.Types[TSTRING],
+
+ // basic type aliases
+ types.Bytetype,
+ types.Runetype,
+
+ // error
+ types.Errortype,
+
+ // untyped types
+ types.UntypedBool,
+ types.UntypedInt,
+ types.UntypedRune,
+ types.UntypedFloat,
+ types.UntypedComplex,
+ types.UntypedString,
+ types.Types[TNIL],
+
+ // package unsafe
+ types.Types[TUNSAFEPTR],
+
+ // invalid type (package contains errors)
+ types.Types[Txxx],
+
+ // any type, for builtin export data
+ types.Types[TANY],
+ }
+ }
+ return predecl
+}
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
new file mode 100644
index 0000000..911ac4c
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -0,0 +1,24 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/internal/src"
+)
+
+// 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 npos(pos src.XPos, n *Node) *Node {
+ n.Pos = pos
+ return n
+}
+
+func builtinCall(op Op) *Node {
+ return nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil)
+}
diff --git a/src/cmd/compile/internal/gc/bitset.go b/src/cmd/compile/internal/gc/bitset.go
new file mode 100644
index 0000000..ed5eea0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bitset.go
@@ -0,0 +1,59 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+type bitset8 uint8
+
+func (f *bitset8) set(mask uint8, b bool) {
+ if b {
+ *(*uint8)(f) |= mask
+ } else {
+ *(*uint8)(f) &^= mask
+ }
+}
+
+type bitset16 uint16
+
+func (f *bitset16) set(mask uint16, b bool) {
+ if b {
+ *(*uint16)(f) |= mask
+ } else {
+ *(*uint16)(f) &^= mask
+ }
+}
+
+type bitset32 uint32
+
+func (f *bitset32) set(mask uint32, b bool) {
+ if b {
+ *(*uint32)(f) |= mask
+ } else {
+ *(*uint32)(f) &^= mask
+ }
+}
+
+func (f bitset32) get2(shift uint8) uint8 {
+ return uint8(f>>shift) & 3
+}
+
+// set2 sets two bits in f using the bottom two bits of b.
+func (f *bitset32) set2(shift uint8, b uint8) {
+ // Clear old bits.
+ *(*uint32)(f) &^= 3 << shift
+ // Set new bits.
+ *(*uint32)(f) |= uint32(b&3) << shift
+}
+
+func (f bitset32) get3(shift uint8) uint8 {
+ return uint8(f>>shift) & 7
+}
+
+// set3 sets three bits in f using the bottom three bits of b.
+func (f *bitset32) set3(shift uint8, b uint8) {
+ // Clear old bits.
+ *(*uint32)(f) &^= 7 << shift
+ // Set new bits.
+ *(*uint32)(f) |= uint32(b&7) << shift
+}
diff --git a/src/cmd/compile/internal/gc/bootstrap.go b/src/cmd/compile/internal/gc/bootstrap.go
new file mode 100644
index 0000000..967f75a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bootstrap.go
@@ -0,0 +1,13 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.8
+
+package gc
+
+import "runtime"
+
+func startMutexProfiling() {
+ Fatalf("mutex profiling unavailable in version %v", runtime.Version())
+}
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
new file mode 100644
index 0000000..e04f23e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -0,0 +1,340 @@
+// Code generated by mkbuiltin.go. DO NOT EDIT.
+
+package gc
+
+import "cmd/compile/internal/types"
+
+var runtimeDecls = [...]struct {
+ name string
+ tag int
+ typ int
+}{
+ {"newobject", funcTag, 4},
+ {"mallocgc", funcTag, 8},
+ {"panicdivide", funcTag, 9},
+ {"panicshift", funcTag, 9},
+ {"panicmakeslicelen", funcTag, 9},
+ {"panicmakeslicecap", funcTag, 9},
+ {"throwinit", funcTag, 9},
+ {"panicwrap", funcTag, 9},
+ {"gopanic", funcTag, 11},
+ {"gorecover", funcTag, 14},
+ {"goschedguarded", funcTag, 9},
+ {"goPanicIndex", funcTag, 16},
+ {"goPanicIndexU", funcTag, 18},
+ {"goPanicSliceAlen", funcTag, 16},
+ {"goPanicSliceAlenU", funcTag, 18},
+ {"goPanicSliceAcap", funcTag, 16},
+ {"goPanicSliceAcapU", funcTag, 18},
+ {"goPanicSliceB", funcTag, 16},
+ {"goPanicSliceBU", funcTag, 18},
+ {"goPanicSlice3Alen", funcTag, 16},
+ {"goPanicSlice3AlenU", funcTag, 18},
+ {"goPanicSlice3Acap", funcTag, 16},
+ {"goPanicSlice3AcapU", funcTag, 18},
+ {"goPanicSlice3B", funcTag, 16},
+ {"goPanicSlice3BU", funcTag, 18},
+ {"goPanicSlice3C", funcTag, 16},
+ {"goPanicSlice3CU", funcTag, 18},
+ {"printbool", funcTag, 19},
+ {"printfloat", funcTag, 21},
+ {"printint", funcTag, 23},
+ {"printhex", funcTag, 25},
+ {"printuint", funcTag, 25},
+ {"printcomplex", funcTag, 27},
+ {"printstring", funcTag, 29},
+ {"printpointer", funcTag, 30},
+ {"printuintptr", funcTag, 31},
+ {"printiface", funcTag, 30},
+ {"printeface", funcTag, 30},
+ {"printslice", funcTag, 30},
+ {"printnl", funcTag, 9},
+ {"printsp", funcTag, 9},
+ {"printlock", funcTag, 9},
+ {"printunlock", funcTag, 9},
+ {"concatstring2", funcTag, 34},
+ {"concatstring3", funcTag, 35},
+ {"concatstring4", funcTag, 36},
+ {"concatstring5", funcTag, 37},
+ {"concatstrings", funcTag, 39},
+ {"cmpstring", funcTag, 40},
+ {"intstring", funcTag, 43},
+ {"slicebytetostring", funcTag, 44},
+ {"slicebytetostringtmp", funcTag, 45},
+ {"slicerunetostring", funcTag, 48},
+ {"stringtoslicebyte", funcTag, 50},
+ {"stringtoslicerune", funcTag, 53},
+ {"slicecopy", funcTag, 54},
+ {"decoderune", funcTag, 55},
+ {"countrunes", funcTag, 56},
+ {"convI2I", funcTag, 57},
+ {"convT16", funcTag, 58},
+ {"convT32", funcTag, 58},
+ {"convT64", funcTag, 58},
+ {"convTstring", funcTag, 58},
+ {"convTslice", funcTag, 58},
+ {"convT2E", funcTag, 59},
+ {"convT2Enoptr", funcTag, 59},
+ {"convT2I", funcTag, 59},
+ {"convT2Inoptr", funcTag, 59},
+ {"assertE2I", funcTag, 57},
+ {"assertE2I2", funcTag, 60},
+ {"assertI2I", funcTag, 57},
+ {"assertI2I2", funcTag, 60},
+ {"panicdottypeE", funcTag, 61},
+ {"panicdottypeI", funcTag, 61},
+ {"panicnildottype", funcTag, 62},
+ {"ifaceeq", funcTag, 64},
+ {"efaceeq", funcTag, 64},
+ {"fastrand", funcTag, 66},
+ {"makemap64", funcTag, 68},
+ {"makemap", funcTag, 69},
+ {"makemap_small", funcTag, 70},
+ {"mapaccess1", funcTag, 71},
+ {"mapaccess1_fast32", funcTag, 72},
+ {"mapaccess1_fast64", funcTag, 72},
+ {"mapaccess1_faststr", funcTag, 72},
+ {"mapaccess1_fat", funcTag, 73},
+ {"mapaccess2", funcTag, 74},
+ {"mapaccess2_fast32", funcTag, 75},
+ {"mapaccess2_fast64", funcTag, 75},
+ {"mapaccess2_faststr", funcTag, 75},
+ {"mapaccess2_fat", funcTag, 76},
+ {"mapassign", funcTag, 71},
+ {"mapassign_fast32", funcTag, 72},
+ {"mapassign_fast32ptr", funcTag, 72},
+ {"mapassign_fast64", funcTag, 72},
+ {"mapassign_fast64ptr", funcTag, 72},
+ {"mapassign_faststr", funcTag, 72},
+ {"mapiterinit", funcTag, 77},
+ {"mapdelete", funcTag, 77},
+ {"mapdelete_fast32", funcTag, 78},
+ {"mapdelete_fast64", funcTag, 78},
+ {"mapdelete_faststr", funcTag, 78},
+ {"mapiternext", funcTag, 79},
+ {"mapclear", funcTag, 80},
+ {"makechan64", funcTag, 82},
+ {"makechan", funcTag, 83},
+ {"chanrecv1", funcTag, 85},
+ {"chanrecv2", funcTag, 86},
+ {"chansend1", funcTag, 88},
+ {"closechan", funcTag, 30},
+ {"writeBarrier", varTag, 90},
+ {"typedmemmove", funcTag, 91},
+ {"typedmemclr", funcTag, 92},
+ {"typedslicecopy", funcTag, 93},
+ {"selectnbsend", funcTag, 94},
+ {"selectnbrecv", funcTag, 95},
+ {"selectnbrecv2", funcTag, 97},
+ {"selectsetpc", funcTag, 98},
+ {"selectgo", funcTag, 99},
+ {"block", funcTag, 9},
+ {"makeslice", funcTag, 100},
+ {"makeslice64", funcTag, 101},
+ {"makeslicecopy", funcTag, 102},
+ {"growslice", funcTag, 104},
+ {"memmove", funcTag, 105},
+ {"memclrNoHeapPointers", funcTag, 106},
+ {"memclrHasPointers", funcTag, 106},
+ {"memequal", funcTag, 107},
+ {"memequal0", funcTag, 108},
+ {"memequal8", funcTag, 108},
+ {"memequal16", funcTag, 108},
+ {"memequal32", funcTag, 108},
+ {"memequal64", funcTag, 108},
+ {"memequal128", funcTag, 108},
+ {"f32equal", funcTag, 109},
+ {"f64equal", funcTag, 109},
+ {"c64equal", funcTag, 109},
+ {"c128equal", funcTag, 109},
+ {"strequal", funcTag, 109},
+ {"interequal", funcTag, 109},
+ {"nilinterequal", funcTag, 109},
+ {"memhash", funcTag, 110},
+ {"memhash0", funcTag, 111},
+ {"memhash8", funcTag, 111},
+ {"memhash16", funcTag, 111},
+ {"memhash32", funcTag, 111},
+ {"memhash64", funcTag, 111},
+ {"memhash128", funcTag, 111},
+ {"f32hash", funcTag, 111},
+ {"f64hash", funcTag, 111},
+ {"c64hash", funcTag, 111},
+ {"c128hash", funcTag, 111},
+ {"strhash", funcTag, 111},
+ {"interhash", funcTag, 111},
+ {"nilinterhash", funcTag, 111},
+ {"int64div", funcTag, 112},
+ {"uint64div", funcTag, 113},
+ {"int64mod", funcTag, 112},
+ {"uint64mod", funcTag, 113},
+ {"float64toint64", funcTag, 114},
+ {"float64touint64", funcTag, 115},
+ {"float64touint32", funcTag, 116},
+ {"int64tofloat64", funcTag, 117},
+ {"uint64tofloat64", funcTag, 118},
+ {"uint32tofloat64", funcTag, 119},
+ {"complex128div", funcTag, 120},
+ {"racefuncenter", funcTag, 31},
+ {"racefuncenterfp", funcTag, 9},
+ {"racefuncexit", funcTag, 9},
+ {"raceread", funcTag, 31},
+ {"racewrite", funcTag, 31},
+ {"racereadrange", funcTag, 121},
+ {"racewriterange", funcTag, 121},
+ {"msanread", funcTag, 121},
+ {"msanwrite", funcTag, 121},
+ {"msanmove", funcTag, 122},
+ {"checkptrAlignment", funcTag, 123},
+ {"checkptrArithmetic", funcTag, 125},
+ {"libfuzzerTraceCmp1", funcTag, 127},
+ {"libfuzzerTraceCmp2", funcTag, 129},
+ {"libfuzzerTraceCmp4", funcTag, 130},
+ {"libfuzzerTraceCmp8", funcTag, 131},
+ {"libfuzzerTraceConstCmp1", funcTag, 127},
+ {"libfuzzerTraceConstCmp2", funcTag, 129},
+ {"libfuzzerTraceConstCmp4", funcTag, 130},
+ {"libfuzzerTraceConstCmp8", funcTag, 131},
+ {"x86HasPOPCNT", varTag, 6},
+ {"x86HasSSE41", varTag, 6},
+ {"x86HasFMA", varTag, 6},
+ {"armHasVFPv4", varTag, 6},
+ {"arm64HasATOMICS", varTag, 6},
+}
+
+func runtimeTypes() []*types.Type {
+ var typs [132]*types.Type
+ typs[0] = types.Bytetype
+ typs[1] = types.NewPtr(typs[0])
+ typs[2] = types.Types[TANY]
+ typs[3] = types.NewPtr(typs[2])
+ typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
+ typs[5] = types.Types[TUINTPTR]
+ typs[6] = types.Types[TBOOL]
+ typs[7] = types.Types[TUNSAFEPTR]
+ typs[8] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*Node{anonfield(typs[7])})
+ typs[9] = functype(nil, nil, nil)
+ typs[10] = types.Types[TINTER]
+ typs[11] = functype(nil, []*Node{anonfield(typs[10])}, nil)
+ typs[12] = types.Types[TINT32]
+ typs[13] = types.NewPtr(typs[12])
+ typs[14] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[10])})
+ typs[15] = types.Types[TINT]
+ typs[16] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
+ typs[17] = types.Types[TUINT]
+ typs[18] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
+ typs[19] = functype(nil, []*Node{anonfield(typs[6])}, nil)
+ typs[20] = types.Types[TFLOAT64]
+ typs[21] = functype(nil, []*Node{anonfield(typs[20])}, nil)
+ typs[22] = types.Types[TINT64]
+ typs[23] = functype(nil, []*Node{anonfield(typs[22])}, nil)
+ typs[24] = types.Types[TUINT64]
+ typs[25] = functype(nil, []*Node{anonfield(typs[24])}, nil)
+ typs[26] = types.Types[TCOMPLEX128]
+ typs[27] = functype(nil, []*Node{anonfield(typs[26])}, nil)
+ typs[28] = types.Types[TSTRING]
+ typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
+ typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
+ typs[31] = functype(nil, []*Node{anonfield(typs[5])}, nil)
+ typs[32] = types.NewArray(typs[0], 32)
+ typs[33] = types.NewPtr(typs[32])
+ typs[34] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[35] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[36] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[37] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[38] = types.NewSlice(typs[28])
+ typs[39] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[38])}, []*Node{anonfield(typs[28])})
+ typs[40] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
+ typs[41] = types.NewArray(typs[0], 4)
+ typs[42] = types.NewPtr(typs[41])
+ typs[43] = functype(nil, []*Node{anonfield(typs[42]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
+ typs[44] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
+ typs[45] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
+ typs[46] = types.Runetype
+ typs[47] = types.NewSlice(typs[46])
+ typs[48] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[47])}, []*Node{anonfield(typs[28])})
+ typs[49] = types.NewSlice(typs[0])
+ typs[50] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28])}, []*Node{anonfield(typs[49])})
+ typs[51] = types.NewArray(typs[46], 32)
+ typs[52] = types.NewPtr(typs[51])
+ typs[53] = functype(nil, []*Node{anonfield(typs[52]), anonfield(typs[28])}, []*Node{anonfield(typs[47])})
+ typs[54] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
+ typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[46]), anonfield(typs[15])})
+ typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
+ typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
+ typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
+ typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
+ typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
+ typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
+ typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
+ typs[63] = types.NewPtr(typs[5])
+ typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
+ typs[65] = types.Types[TUINT32]
+ typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
+ typs[67] = types.NewMap(typs[2], typs[2])
+ typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
+ typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
+ typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
+ typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
+ typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
+ typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
+ typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
+ typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
+ typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
+ typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
+ typs[81] = types.NewChan(typs[2], types.Cboth)
+ typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
+ typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
+ typs[84] = types.NewChan(typs[2], types.Crecv)
+ typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
+ typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[87] = types.NewChan(typs[2], types.Csend)
+ typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
+ typs[89] = types.NewArray(typs[0], 3)
+ typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
+ typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
+ typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
+ typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
+ typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
+ typs[96] = types.NewPtr(typs[6])
+ typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
+ typs[98] = functype(nil, []*Node{anonfield(typs[63])}, nil)
+ typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
+ typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
+ typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
+ typs[102] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
+ typs[103] = types.NewSlice(typs[2])
+ typs[104] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[103]), anonfield(typs[15])}, []*Node{anonfield(typs[103])})
+ typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
+ typs[106] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
+ typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
+ typs[108] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
+ typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
+ typs[111] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
+ typs[112] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
+ typs[113] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
+ typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
+ typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
+ typs[116] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
+ typs[117] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
+ typs[118] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
+ typs[119] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
+ typs[120] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
+ typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
+ typs[122] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5]), anonfield(typs[5])}, nil)
+ typs[123] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
+ typs[124] = types.NewSlice(typs[7])
+ typs[125] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[124])}, nil)
+ typs[126] = types.Types[TUINT8]
+ typs[127] = functype(nil, []*Node{anonfield(typs[126]), anonfield(typs[126])}, nil)
+ typs[128] = types.Types[TUINT16]
+ typs[129] = functype(nil, []*Node{anonfield(typs[128]), anonfield(typs[128])}, nil)
+ typs[130] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
+ typs[131] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
+ return typs[:]
+}
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
new file mode 100644
index 0000000..acb69c7
--- /dev/null
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -0,0 +1,259 @@
+// Copyright 2009 The Go 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 runtime
+
+// emitted by compiler, not referred to by go programs
+
+import "unsafe"
+
+func newobject(typ *byte) *any
+func mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
+func panicdivide()
+func panicshift()
+func panicmakeslicelen()
+func panicmakeslicecap()
+func throwinit()
+func panicwrap()
+
+func gopanic(interface{})
+func gorecover(*int32) interface{}
+func goschedguarded()
+
+// Note: these declarations are just for wasm port.
+// Other ports call assembly stubs instead.
+func goPanicIndex(x int, y int)
+func goPanicIndexU(x uint, y int)
+func goPanicSliceAlen(x int, y int)
+func goPanicSliceAlenU(x uint, y int)
+func goPanicSliceAcap(x int, y int)
+func goPanicSliceAcapU(x uint, y int)
+func goPanicSliceB(x int, y int)
+func goPanicSliceBU(x uint, y int)
+func goPanicSlice3Alen(x int, y int)
+func goPanicSlice3AlenU(x uint, y int)
+func goPanicSlice3Acap(x int, y int)
+func goPanicSlice3AcapU(x uint, y int)
+func goPanicSlice3B(x int, y int)
+func goPanicSlice3BU(x uint, y int)
+func goPanicSlice3C(x int, y int)
+func goPanicSlice3CU(x uint, y int)
+
+func printbool(bool)
+func printfloat(float64)
+func printint(int64)
+func printhex(uint64)
+func printuint(uint64)
+func printcomplex(complex128)
+func printstring(string)
+func printpointer(any)
+func printuintptr(uintptr)
+func printiface(any)
+func printeface(any)
+func printslice(any)
+func printnl()
+func printsp()
+func printlock()
+func printunlock()
+
+func concatstring2(*[32]byte, string, string) string
+func concatstring3(*[32]byte, string, string, string) string
+func concatstring4(*[32]byte, string, string, string, string) string
+func concatstring5(*[32]byte, string, string, string, string, string) string
+func concatstrings(*[32]byte, []string) string
+
+func cmpstring(string, string) int
+func intstring(*[4]byte, int64) string
+func slicebytetostring(buf *[32]byte, ptr *byte, n int) string
+func slicebytetostringtmp(ptr *byte, n int) string
+func slicerunetostring(*[32]byte, []rune) string
+func stringtoslicebyte(*[32]byte, string) []byte
+func stringtoslicerune(*[32]rune, string) []rune
+func slicecopy(toPtr *any, toLen int, fromPtr *any, fromLen int, wid uintptr) int
+
+func decoderune(string, int) (retv rune, retk int)
+func countrunes(string) int
+
+// Non-empty-interface to non-empty-interface conversion.
+func convI2I(typ *byte, elem any) (ret any)
+
+// Specialized type-to-interface conversion.
+// These return only a data pointer.
+func convT16(val any) unsafe.Pointer // val must be uint16-like (same size and alignment as a uint16)
+func convT32(val any) unsafe.Pointer // val must be uint32-like (same size and alignment as a uint32)
+func convT64(val any) unsafe.Pointer // val must be uint64-like (same size and alignment as a uint64 and contains no pointers)
+func convTstring(val any) unsafe.Pointer // val must be a string
+func convTslice(val any) unsafe.Pointer // val must be a slice
+
+// Type to empty-interface conversion.
+func convT2E(typ *byte, elem *any) (ret any)
+func convT2Enoptr(typ *byte, elem *any) (ret any)
+
+// Type to non-empty-interface conversion.
+func convT2I(tab *byte, elem *any) (ret any)
+func convT2Inoptr(tab *byte, elem *any) (ret any)
+
+// interface type assertions x.(T)
+func assertE2I(typ *byte, iface any) (ret any)
+func assertE2I2(typ *byte, iface any) (ret any, b bool)
+func assertI2I(typ *byte, iface any) (ret any)
+func assertI2I2(typ *byte, iface any) (ret any, b bool)
+func panicdottypeE(have, want, iface *byte)
+func panicdottypeI(have, want, iface *byte)
+func panicnildottype(want *byte)
+
+// interface equality. Type/itab pointers are already known to be equal, so
+// we only need to pass one.
+func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
+func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
+
+func fastrand() uint32
+
+// *byte is really *runtime.Type
+func makemap64(mapType *byte, hint int64, mapbuf *any) (hmap map[any]any)
+func makemap(mapType *byte, hint int, mapbuf *any) (hmap map[any]any)
+func makemap_small() (hmap map[any]any)
+func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
+func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess1_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (val *any)
+func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool)
+func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapaccess2_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (val *any, pres bool)
+func mapassign(mapType *byte, hmap map[any]any, key *any) (val *any)
+func mapassign_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapassign_fast32ptr(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapassign_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapassign_fast64ptr(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapassign_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
+func mapdelete(mapType *byte, hmap map[any]any, key *any)
+func mapdelete_fast32(mapType *byte, hmap map[any]any, key any)
+func mapdelete_fast64(mapType *byte, hmap map[any]any, key any)
+func mapdelete_faststr(mapType *byte, hmap map[any]any, key any)
+func mapiternext(hiter *any)
+func mapclear(mapType *byte, hmap map[any]any)
+
+// *byte is really *runtime.Type
+func makechan64(chanType *byte, size int64) (hchan chan any)
+func makechan(chanType *byte, size int) (hchan chan any)
+func chanrecv1(hchan <-chan any, elem *any)
+func chanrecv2(hchan <-chan any, elem *any) bool
+func chansend1(hchan chan<- any, elem *any)
+func closechan(hchan any)
+
+var writeBarrier struct {
+ enabled bool
+ pad [3]byte
+ needed bool
+ cgo bool
+ alignme uint64
+}
+
+// *byte is really *runtime.Type
+func typedmemmove(typ *byte, dst *any, src *any)
+func typedmemclr(typ *byte, dst *any)
+func typedslicecopy(typ *byte, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
+
+func selectnbsend(hchan chan<- any, elem *any) bool
+func selectnbrecv(elem *any, hchan <-chan any) bool
+func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool
+
+func selectsetpc(pc *uintptr)
+func selectgo(cas0 *byte, order0 *byte, pc0 *uintptr, nsends int, nrecvs int, block bool) (int, bool)
+func block()
+
+func makeslice(typ *byte, len int, cap int) unsafe.Pointer
+func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer
+func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
+func growslice(typ *byte, old []any, cap int) (ary []any)
+func memmove(to *any, frm *any, length uintptr)
+func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
+func memclrHasPointers(ptr unsafe.Pointer, n uintptr)
+
+func memequal(x, y *any, size uintptr) bool
+func memequal0(x, y *any) bool
+func memequal8(x, y *any) bool
+func memequal16(x, y *any) bool
+func memequal32(x, y *any) bool
+func memequal64(x, y *any) bool
+func memequal128(x, y *any) bool
+func f32equal(p, q unsafe.Pointer) bool
+func f64equal(p, q unsafe.Pointer) bool
+func c64equal(p, q unsafe.Pointer) bool
+func c128equal(p, q unsafe.Pointer) bool
+func strequal(p, q unsafe.Pointer) bool
+func interequal(p, q unsafe.Pointer) bool
+func nilinterequal(p, q unsafe.Pointer) bool
+
+func memhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr
+func memhash0(p unsafe.Pointer, h uintptr) uintptr
+func memhash8(p unsafe.Pointer, h uintptr) uintptr
+func memhash16(p unsafe.Pointer, h uintptr) uintptr
+func memhash32(p unsafe.Pointer, h uintptr) uintptr
+func memhash64(p unsafe.Pointer, h uintptr) uintptr
+func memhash128(p unsafe.Pointer, h uintptr) uintptr
+func f32hash(p unsafe.Pointer, h uintptr) uintptr
+func f64hash(p unsafe.Pointer, h uintptr) uintptr
+func c64hash(p unsafe.Pointer, h uintptr) uintptr
+func c128hash(p unsafe.Pointer, h uintptr) uintptr
+func strhash(a unsafe.Pointer, h uintptr) uintptr
+func interhash(p unsafe.Pointer, h uintptr) uintptr
+func nilinterhash(p unsafe.Pointer, h uintptr) uintptr
+
+// only used on 32-bit
+func int64div(int64, int64) int64
+func uint64div(uint64, uint64) uint64
+func int64mod(int64, int64) int64
+func uint64mod(uint64, uint64) uint64
+func float64toint64(float64) int64
+func float64touint64(float64) uint64
+func float64touint32(float64) uint32
+func int64tofloat64(int64) float64
+func uint64tofloat64(uint64) float64
+func uint32tofloat64(uint32) float64
+
+func complex128div(num complex128, den complex128) (quo complex128)
+
+// race detection
+func racefuncenter(uintptr)
+func racefuncenterfp()
+func racefuncexit()
+func raceread(uintptr)
+func racewrite(uintptr)
+func racereadrange(addr, size uintptr)
+func racewriterange(addr, size uintptr)
+
+// memory sanitizer
+func msanread(addr, size uintptr)
+func msanwrite(addr, size uintptr)
+func msanmove(dst, src, size uintptr)
+
+func checkptrAlignment(unsafe.Pointer, *byte, uintptr)
+func checkptrArithmetic(unsafe.Pointer, []unsafe.Pointer)
+
+func libfuzzerTraceCmp1(uint8, uint8)
+func libfuzzerTraceCmp2(uint16, uint16)
+func libfuzzerTraceCmp4(uint32, uint32)
+func libfuzzerTraceCmp8(uint64, uint64)
+func libfuzzerTraceConstCmp1(uint8, uint8)
+func libfuzzerTraceConstCmp2(uint16, uint16)
+func libfuzzerTraceConstCmp4(uint32, uint32)
+func libfuzzerTraceConstCmp8(uint64, uint64)
+
+// architecture variants
+var x86HasPOPCNT bool
+var x86HasSSE41 bool
+var x86HasFMA bool
+var armHasVFPv4 bool
+var arm64HasATOMICS bool
diff --git a/src/cmd/compile/internal/gc/builtin_test.go b/src/cmd/compile/internal/gc/builtin_test.go
new file mode 100644
index 0000000..57f24b2
--- /dev/null
+++ b/src/cmd/compile/internal/gc/builtin_test.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 gc_test
+
+import (
+ "bytes"
+ "internal/testenv"
+ "io/ioutil"
+ "os/exec"
+ "testing"
+)
+
+func TestBuiltin(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+ t.Parallel()
+
+ old, err := ioutil.ReadFile("builtin.go")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ new, err := exec.Command(testenv.GoToolPath(t), "run", "mkbuiltin.go", "-stdout").Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Equal(old, new) {
+ t.Fatal("builtin.go out of date; run mkbuiltin.go")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go
new file mode 100644
index 0000000..e32ab97
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bv.go
@@ -0,0 +1,278 @@
+// Copyright 2013 The Go Authors. 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 (
+ "math/bits"
+)
+
+const (
+ wordBits = 32
+ wordMask = wordBits - 1
+ wordShift = 5
+)
+
+// A bvec is a bit vector.
+type bvec struct {
+ n int32 // number of bits in vector
+ b []uint32 // words holding bits
+}
+
+func bvalloc(n int32) bvec {
+ nword := (n + wordBits - 1) / wordBits
+ return bvec{n, make([]uint32, nword)}
+}
+
+type bulkBvec struct {
+ words []uint32
+ nbit int32
+ nword int32
+}
+
+func bvbulkalloc(nbit int32, count int32) bulkBvec {
+ nword := (nbit + wordBits - 1) / wordBits
+ size := int64(nword) * int64(count)
+ if int64(int32(size*4)) != size*4 {
+ Fatalf("bvbulkalloc too big: nbit=%d count=%d nword=%d size=%d", nbit, count, nword, size)
+ }
+ return bulkBvec{
+ words: make([]uint32, size),
+ nbit: nbit,
+ nword: nword,
+ }
+}
+
+func (b *bulkBvec) next() bvec {
+ out := bvec{b.nbit, b.words[:b.nword]}
+ b.words = b.words[b.nword:]
+ return out
+}
+
+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)
+ }
+ for i, x := range bv1.b {
+ if x != bv2.b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func (dst bvec) Copy(src bvec) {
+ copy(dst.b, src.b)
+}
+
+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)
+ }
+ 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
+}
+
+func (bv bvec) Unset(i int32) {
+ if i < 0 || i >= bv.n {
+ Fatalf("bvunset: index %d is out of bounds with length %d\n", i, bv.n)
+ }
+ mask := uint32(1 << uint(i%wordBits))
+ bv.b[i/wordBits] &^= mask
+}
+
+// bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
+// If there is no such index, bvnext returns -1.
+func (bv bvec) Next(i int32) int32 {
+ if i >= bv.n {
+ return -1
+ }
+
+ // Jump i ahead to next word with bits.
+ if bv.b[i>>wordShift]>>uint(i&wordMask) == 0 {
+ i &^= wordMask
+ i += wordBits
+ for i < bv.n && bv.b[i>>wordShift] == 0 {
+ i += wordBits
+ }
+ }
+
+ if i >= bv.n {
+ return -1
+ }
+
+ // Find 1 bit.
+ w := bv.b[i>>wordShift] >> uint(i&wordMask)
+ i += int32(bits.TrailingZeros32(w))
+
+ return i
+}
+
+func (bv bvec) IsEmpty() bool {
+ for _, x := range bv.b {
+ if x != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+func (bv bvec) Not() {
+ for i, x := range bv.b {
+ bv.b[i] = ^x
+ }
+}
+
+// union
+func (dst bvec) Or(src1, src2 bvec) {
+ if len(src1.b) == 0 {
+ return
+ }
+ _, _ = dst.b[len(src1.b)-1], src2.b[len(src1.b)-1] // hoist bounds checks out of the loop
+
+ for i, x := range src1.b {
+ dst.b[i] = x | src2.b[i]
+ }
+}
+
+// intersection
+func (dst bvec) And(src1, src2 bvec) {
+ if len(src1.b) == 0 {
+ return
+ }
+ _, _ = dst.b[len(src1.b)-1], src2.b[len(src1.b)-1] // hoist bounds checks out of the loop
+
+ for i, x := range src1.b {
+ dst.b[i] = x & src2.b[i]
+ }
+}
+
+// difference
+func (dst bvec) AndNot(src1, src2 bvec) {
+ if len(src1.b) == 0 {
+ return
+ }
+ _, _ = dst.b[len(src1.b)-1], src2.b[len(src1.b)-1] // hoist bounds checks out of the loop
+
+ for i, x := range src1.b {
+ dst.b[i] = x &^ src2.b[i]
+ }
+}
+
+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 (bv bvec) Clear() {
+ for i := range bv.b {
+ bv.b[i] = 0
+ }
+}
+
+// FNV-1 hash function constants.
+const (
+ H0 = 2166136261
+ Hp = 16777619
+)
+
+func hashbitmap(h uint32, bv bvec) uint32 {
+ n := int((bv.n + 31) / 32)
+ for i := 0; i < n; i++ {
+ w := bv.b[i]
+ h = (h * Hp) ^ (w & 0xff)
+ h = (h * Hp) ^ ((w >> 8) & 0xff)
+ h = (h * Hp) ^ ((w >> 16) & 0xff)
+ h = (h * Hp) ^ ((w >> 24) & 0xff)
+ }
+
+ return h
+}
+
+// bvecSet is a set of bvecs, in initial insertion order.
+type bvecSet struct {
+ index []int // hash -> uniq index. -1 indicates empty slot.
+ uniq []bvec // unique bvecs, in insertion order
+}
+
+func (m *bvecSet) grow() {
+ // Allocate new index.
+ n := len(m.index) * 2
+ if n == 0 {
+ n = 32
+ }
+ newIndex := make([]int, n)
+ for i := range newIndex {
+ newIndex[i] = -1
+ }
+
+ // Rehash into newIndex.
+ for i, bv := range m.uniq {
+ h := hashbitmap(H0, bv) % uint32(len(newIndex))
+ for {
+ j := newIndex[h]
+ if j < 0 {
+ newIndex[h] = i
+ break
+ }
+ h++
+ if h == uint32(len(newIndex)) {
+ h = 0
+ }
+ }
+ }
+ m.index = newIndex
+}
+
+// add adds bv to the set and returns its index in m.extractUniqe.
+// The caller must not modify bv after this.
+func (m *bvecSet) add(bv bvec) int {
+ if len(m.uniq)*4 >= len(m.index) {
+ m.grow()
+ }
+
+ index := m.index
+ h := hashbitmap(H0, bv) % uint32(len(index))
+ for {
+ j := index[h]
+ if j < 0 {
+ // New bvec.
+ index[h] = len(m.uniq)
+ m.uniq = append(m.uniq, bv)
+ return len(m.uniq) - 1
+ }
+ jlive := m.uniq[j]
+ if bv.Eq(jlive) {
+ // Existing bvec.
+ return j
+ }
+
+ h++
+ if h == uint32(len(index)) {
+ h = 0
+ }
+ }
+}
+
+// extractUniqe returns this slice of unique bit vectors in m, as
+// indexed by the result of bvecSet.add.
+func (m *bvecSet) extractUniqe() []bvec {
+ return m.uniq
+}
diff --git a/src/cmd/compile/internal/gc/class_string.go b/src/cmd/compile/internal/gc/class_string.go
new file mode 100644
index 0000000..a4084a7
--- /dev/null
+++ b/src/cmd/compile/internal/gc/class_string.go
@@ -0,0 +1,29 @@
+// Code generated by "stringer -type=Class"; DO NOT EDIT.
+
+package gc
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[Pxxx-0]
+ _ = x[PEXTERN-1]
+ _ = x[PAUTO-2]
+ _ = x[PAUTOHEAP-3]
+ _ = x[PPARAM-4]
+ _ = x[PPARAMOUT-5]
+ _ = x[PFUNC-6]
+}
+
+const _Class_name = "PxxxPEXTERNPAUTOPAUTOHEAPPPARAMPPARAMOUTPFUNC"
+
+var _Class_index = [...]uint8{0, 4, 11, 16, 25, 31, 40, 45}
+
+func (i Class) String() string {
+ if i >= Class(len(_Class_index)-1) {
+ return "Class(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Class_name[_Class_index[i]:_Class_index[i+1]]
+}
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
new file mode 100644
index 0000000..bd350f6
--- /dev/null
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -0,0 +1,594 @@
+// Copyright 2009 The Go Authors. 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/syntax"
+ "cmd/compile/internal/types"
+ "fmt"
+)
+
+func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
+ xtype := p.typeExpr(expr.Type)
+ ntype := p.typeExpr(expr.Type)
+
+ xfunc := p.nod(expr, ODCLFUNC, nil, nil)
+ xfunc.Func.SetIsHiddenClosure(Curfn != nil)
+ xfunc.Func.Nname = newfuncnamel(p.pos(expr), nblank.Sym) // filled in by typecheckclosure
+ xfunc.Func.Nname.Name.Param.Ntype = xtype
+ xfunc.Func.Nname.Name.Defn = xfunc
+
+ clo := p.nod(expr, OCLOSURE, nil, nil)
+ clo.Func.Ntype = ntype
+
+ xfunc.Func.Closure = clo
+ clo.Func.Closure = xfunc
+
+ p.funcBody(xfunc, expr.Body)
+
+ // closure-specific variables are hanging off the
+ // ordinary ones in the symbol table; see oldname.
+ // unhook them.
+ // make the list of pointers for the closure call.
+ for _, v := range xfunc.Func.Cvars.Slice() {
+ // Unlink from v1; see comment in syntax.go type Param for these fields.
+ v1 := v.Name.Defn
+ v1.Name.Param.Innermost = v.Name.Param.Outer
+
+ // If the closure usage of v is not dense,
+ // we need to make it dense; now that we're out
+ // of the function in which v appeared,
+ // look up v.Sym in the enclosing function
+ // and keep it around for use in the compiled code.
+ //
+ // That is, suppose we just finished parsing the innermost
+ // closure f4 in this code:
+ //
+ // func f() {
+ // v := 1
+ // func() { // f2
+ // use(v)
+ // func() { // f3
+ // func() { // f4
+ // use(v)
+ // }()
+ // }()
+ // }()
+ // }
+ //
+ // At this point v.Outer is f2's v; there is no f3's v.
+ // To construct the closure f4 from within f3,
+ // we need to use f3's v and in this case we need to create f3's v.
+ // We are now in the context of f3, so calling oldname(v.Sym)
+ // obtains f3's v, creating it if necessary (as it is in the example).
+ //
+ // capturevars will decide whether to use v directly or &v.
+ v.Name.Param.Outer = oldname(v.Sym)
+ }
+
+ return clo
+}
+
+// typecheckclosure typechecks an OCLOSURE node. It also creates the named
+// function associated with the closure.
+// TODO: This creation of the named function should probably really be done in a
+// separate pass from type-checking.
+func typecheckclosure(clo *Node, top int) {
+ xfunc := clo.Func.Closure
+ // Set current associated iota value, so iota can be used inside
+ // function in ConstSpec, see issue #22344
+ if x := getIotaValue(); x >= 0 {
+ xfunc.SetIota(x)
+ }
+
+ clo.Func.Ntype = typecheck(clo.Func.Ntype, ctxType)
+ clo.Type = clo.Func.Ntype.Type
+ clo.Func.Top = top
+
+ // Do not typecheck xfunc twice, otherwise, we will end up pushing
+ // xfunc to xtop multiple times, causing initLSym called twice.
+ // See #30709
+ if xfunc.Typecheck() == 1 {
+ return
+ }
+
+ for _, ln := range xfunc.Func.Cvars.Slice() {
+ n := ln.Name.Defn
+ if !n.Name.Captured() {
+ n.Name.SetCaptured(true)
+ if n.Name.Decldepth == 0 {
+ Fatalf("typecheckclosure: var %S does not have decldepth assigned", n)
+ }
+
+ // Ignore assignments to the variable in straightline code
+ // preceding the first capturing by a closure.
+ if n.Name.Decldepth == decldepth {
+ n.Name.SetAssigned(false)
+ }
+ }
+ }
+
+ xfunc.Func.Nname.Sym = closurename(Curfn)
+ setNodeNameFunc(xfunc.Func.Nname)
+ xfunc = typecheck(xfunc, ctxStmt)
+
+ // Type check the body now, but only if we're inside a function.
+ // At top level (in a variable initialization: curfn==nil) we're not
+ // ready to type check code yet; we'll check it later, because the
+ // underlying closure function we create is added to xtop.
+ if Curfn != nil && clo.Type != nil {
+ oldfn := Curfn
+ Curfn = xfunc
+ olddd := decldepth
+ decldepth = 1
+ typecheckslice(xfunc.Nbody.Slice(), ctxStmt)
+ decldepth = olddd
+ Curfn = oldfn
+ }
+
+ xtop = append(xtop, xfunc)
+}
+
+// globClosgen is like Func.Closgen, but for the global scope.
+var globClosgen int
+
+// closurename generates a new unique name for a closure within
+// outerfunc.
+func closurename(outerfunc *Node) *types.Sym {
+ outer := "glob."
+ prefix := "func"
+ gen := &globClosgen
+
+ if outerfunc != nil {
+ if outerfunc.Func.Closure != nil {
+ prefix = ""
+ }
+
+ outer = outerfunc.funcname()
+
+ // There may be multiple functions named "_". In those
+ // cases, we can't use their individual Closgens as it
+ // would lead to name clashes.
+ if !outerfunc.Func.Nname.isBlank() {
+ gen = &outerfunc.Func.Closgen
+ }
+ }
+
+ *gen++
+ return lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
+}
+
+// capturevarscomplete is set to true when the capturevars phase is done.
+var capturevarscomplete bool
+
+// capturevars is called in a separate phase after all typechecking is done.
+// It decides whether each variable captured by a closure should be captured
+// by value or by reference.
+// We use value capturing for values <= 128 bytes that are never reassigned
+// after capturing (effectively constant).
+func capturevars(xfunc *Node) {
+ lno := lineno
+ lineno = xfunc.Pos
+
+ clo := xfunc.Func.Closure
+ cvars := xfunc.Func.Cvars.Slice()
+ out := cvars[:0]
+ for _, v := range cvars {
+ if v.Type == nil {
+ // If v.Type is nil, it means v looked like it
+ // was going to be used in the closure, but
+ // isn't. This happens in struct literals like
+ // s{f: x} where we can't distinguish whether
+ // f is a field identifier or expression until
+ // resolving s.
+ continue
+ }
+ out = append(out, v)
+
+ // type check the & of closed variables outside the closure,
+ // so that the outer frame also grabs them and knows they escape.
+ dowidth(v.Type)
+
+ outer := v.Name.Param.Outer
+ outermost := v.Name.Defn
+
+ // out parameters will be assigned to implicitly upon return.
+ if outermost.Class() != PPARAMOUT && !outermost.Name.Addrtaken() && !outermost.Name.Assigned() && v.Type.Width <= 128 {
+ v.Name.SetByval(true)
+ } else {
+ outermost.Name.SetAddrtaken(true)
+ outer = nod(OADDR, outer, nil)
+ }
+
+ if Debug.m > 1 {
+ var name *types.Sym
+ if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
+ name = v.Name.Curfn.Func.Nname.Sym
+ }
+ how := "ref"
+ if v.Name.Byval() {
+ how = "value"
+ }
+ Warnl(v.Pos, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Name.Addrtaken(), outermost.Name.Assigned(), int32(v.Type.Width))
+ }
+
+ outer = typecheck(outer, ctxExpr)
+ clo.Func.Enter.Append(outer)
+ }
+
+ xfunc.Func.Cvars.Set(out)
+ lineno = lno
+}
+
+// transformclosure is called in a separate phase after escape analysis.
+// It transform closure bodies to properly reference captured variables.
+func transformclosure(xfunc *Node) {
+ lno := lineno
+ lineno = xfunc.Pos
+ clo := xfunc.Func.Closure
+
+ if clo.Func.Top&ctxCallee != 0 {
+ // If the closure is directly called, we transform it to a plain function call
+ // with variables passed as args. This avoids allocation of a closure object.
+ // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
+ // will complete the transformation later.
+ // For illustration, the following closure:
+ // func(a int) {
+ // println(byval)
+ // byref++
+ // }(42)
+ // becomes:
+ // func(byval int, &byref *int, a int) {
+ // println(byval)
+ // (*&byref)++
+ // }(byval, &byref, 42)
+
+ // f is ONAME of the actual function.
+ f := xfunc.Func.Nname
+
+ // We are going to insert captured variables before input args.
+ var params []*types.Field
+ var decls []*Node
+ for _, v := range xfunc.Func.Cvars.Slice() {
+ if !v.Name.Byval() {
+ // If v of type T is captured by reference,
+ // we introduce function param &v *T
+ // and v remains PAUTOHEAP with &v heapaddr
+ // (accesses will implicitly deref &v).
+ addr := newname(lookup("&" + v.Sym.Name))
+ addr.Type = types.NewPtr(v.Type)
+ v.Name.Param.Heapaddr = addr
+ v = addr
+ }
+
+ v.SetClass(PPARAM)
+ decls = append(decls, v)
+
+ fld := types.NewField()
+ fld.Nname = asTypesNode(v)
+ fld.Type = v.Type
+ fld.Sym = v.Sym
+ params = append(params, fld)
+ }
+
+ if len(params) > 0 {
+ // Prepend params and decls.
+ f.Type.Params().SetFields(append(params, f.Type.Params().FieldSlice()...))
+ xfunc.Func.Dcl = append(decls, xfunc.Func.Dcl...)
+ }
+
+ dowidth(f.Type)
+ xfunc.Type = f.Type // update type of ODCLFUNC
+ } else {
+ // The closure is not called, so it is going to stay as closure.
+ var body []*Node
+ offset := int64(Widthptr)
+ for _, v := range xfunc.Func.Cvars.Slice() {
+ // cv refers to the field inside of closure OSTRUCTLIT.
+ cv := nod(OCLOSUREVAR, nil, nil)
+
+ cv.Type = v.Type
+ if !v.Name.Byval() {
+ cv.Type = types.NewPtr(v.Type)
+ }
+ offset = Rnd(offset, int64(cv.Type.Align))
+ cv.Xoffset = offset
+ offset += cv.Type.Width
+
+ if v.Name.Byval() && v.Type.Width <= int64(2*Widthptr) {
+ // If it is a small variable captured by value, downgrade it to PAUTO.
+ v.SetClass(PAUTO)
+ xfunc.Func.Dcl = append(xfunc.Func.Dcl, v)
+ body = append(body, nod(OAS, v, cv))
+ } else {
+ // Declare variable holding addresses taken from closure
+ // and initialize in entry prologue.
+ addr := newname(lookup("&" + v.Sym.Name))
+ addr.Type = types.NewPtr(v.Type)
+ addr.SetClass(PAUTO)
+ addr.Name.SetUsed(true)
+ addr.Name.Curfn = xfunc
+ xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
+ v.Name.Param.Heapaddr = addr
+ if v.Name.Byval() {
+ cv = nod(OADDR, cv, nil)
+ }
+ body = append(body, nod(OAS, addr, cv))
+ }
+ }
+
+ if len(body) > 0 {
+ typecheckslice(body, ctxStmt)
+ xfunc.Func.Enter.Set(body)
+ xfunc.Func.SetNeedctxt(true)
+ }
+ }
+
+ lineno = lno
+}
+
+// hasemptycvars reports whether closure clo has an
+// empty list of captured vars.
+func hasemptycvars(clo *Node) bool {
+ xfunc := clo.Func.Closure
+ return xfunc.Func.Cvars.Len() == 0
+}
+
+// closuredebugruntimecheck applies boilerplate checks for debug flags
+// and compiling runtime
+func closuredebugruntimecheck(clo *Node) {
+ if Debug_closure > 0 {
+ xfunc := clo.Func.Closure
+ if clo.Esc == EscHeap {
+ Warnl(clo.Pos, "heap closure, captured vars = %v", xfunc.Func.Cvars)
+ } else {
+ Warnl(clo.Pos, "stack closure, captured vars = %v", xfunc.Func.Cvars)
+ }
+ }
+ if compiling_runtime && clo.Esc == EscHeap {
+ yyerrorl(clo.Pos, "heap-allocated closure, not allowed in runtime")
+ }
+}
+
+// closureType returns the struct type used to hold all the information
+// needed in the closure for clo (clo must be a OCLOSURE node).
+// The address of a variable of the returned type can be cast to a func.
+func closureType(clo *Node) *types.Type {
+ // Create closure in the form of a composite literal.
+ // supposing the closure captures an int i and a string s
+ // and has one float64 argument and no results,
+ // the generated code looks like:
+ //
+ // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
+ //
+ // The use of the struct provides type information to the garbage
+ // collector so that it can walk the closure. We could use (in this case)
+ // [3]unsafe.Pointer instead, but that would leave the gc in the dark.
+ // The information appears in the binary in the form of type descriptors;
+ // the struct is unnamed so that closures in multiple packages with the
+ // same struct type can share the descriptor.
+ fields := []*Node{
+ namedfield(".F", types.Types[TUINTPTR]),
+ }
+ for _, v := range clo.Func.Closure.Func.Cvars.Slice() {
+ typ := v.Type
+ if !v.Name.Byval() {
+ typ = types.NewPtr(typ)
+ }
+ fields = append(fields, symfield(v.Sym, typ))
+ }
+ typ := tostruct(fields)
+ typ.SetNoalg(true)
+ return typ
+}
+
+func walkclosure(clo *Node, init *Nodes) *Node {
+ xfunc := clo.Func.Closure
+
+ // If no closure vars, don't bother wrapping.
+ if hasemptycvars(clo) {
+ if Debug_closure > 0 {
+ Warnl(clo.Pos, "closure converted to global")
+ }
+ return xfunc.Func.Nname
+ }
+ closuredebugruntimecheck(clo)
+
+ typ := closureType(clo)
+
+ clos := nod(OCOMPLIT, nil, typenod(typ))
+ clos.Esc = clo.Esc
+ clos.List.Set(append([]*Node{nod(OCFUNC, xfunc.Func.Nname, nil)}, clo.Func.Enter.Slice()...))
+
+ clos = nod(OADDR, clos, nil)
+ clos.Esc = clo.Esc
+
+ // Force type conversion from *struct to the func type.
+ clos = convnop(clos, clo.Type)
+
+ // non-escaping temp to use, if any.
+ if x := prealloc[clo]; x != nil {
+ if !types.Identical(typ, x.Type) {
+ panic("closure type does not match order's assigned type")
+ }
+ clos.Left.Right = x
+ delete(prealloc, clo)
+ }
+
+ return walkexpr(clos, init)
+}
+
+func typecheckpartialcall(fn *Node, sym *types.Sym) {
+ switch fn.Op {
+ case ODOTINTER, ODOTMETH:
+ break
+
+ default:
+ Fatalf("invalid typecheckpartialcall")
+ }
+
+ // Create top-level function.
+ xfunc := makepartialcall(fn, fn.Type, sym)
+ fn.Func = xfunc.Func
+ fn.Func.SetWrapper(true)
+ fn.Right = newname(sym)
+ fn.Op = OCALLPART
+ fn.Type = xfunc.Type
+}
+
+// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
+// for partial calls.
+func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
+ rcvrtype := fn.Left.Type
+ sym := methodSymSuffix(rcvrtype, meth, "-fm")
+
+ if sym.Uniq() {
+ return asNode(sym.Def)
+ }
+ sym.SetUniq(true)
+
+ savecurfn := Curfn
+ saveLineNo := lineno
+ Curfn = nil
+
+ // Set line number equal to the line number where the method is declared.
+ var m *types.Field
+ if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() {
+ lineno = m.Pos
+ }
+ // Note: !m.Pos.IsKnown() happens for method expressions where
+ // the method is implicitly declared. The Error method of the
+ // built-in error type is one such method. We leave the line
+ // number at the use of the method expression in this
+ // case. See issue 29389.
+
+ tfn := nod(OTFUNC, nil, nil)
+ tfn.List.Set(structargs(t0.Params(), true))
+ tfn.Rlist.Set(structargs(t0.Results(), false))
+
+ xfunc := dclfunc(sym, tfn)
+ xfunc.Func.SetDupok(true)
+ xfunc.Func.SetNeedctxt(true)
+
+ tfn.Type.SetPkg(t0.Pkg())
+
+ // Declare and initialize variable holding receiver.
+
+ cv := nod(OCLOSUREVAR, nil, nil)
+ cv.Type = rcvrtype
+ cv.Xoffset = Rnd(int64(Widthptr), int64(cv.Type.Align))
+
+ ptr := newname(lookup(".this"))
+ declare(ptr, PAUTO)
+ ptr.Name.SetUsed(true)
+ var body []*Node
+ if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
+ ptr.Type = rcvrtype
+ body = append(body, nod(OAS, ptr, cv))
+ } else {
+ ptr.Type = types.NewPtr(rcvrtype)
+ body = append(body, nod(OAS, ptr, nod(OADDR, cv, nil)))
+ }
+
+ call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil)
+ call.List.Set(paramNnames(tfn.Type))
+ call.SetIsDDD(tfn.Type.IsVariadic())
+ if t0.NumResults() != 0 {
+ n := nod(ORETURN, nil, nil)
+ n.List.Set1(call)
+ call = n
+ }
+ body = append(body, call)
+
+ xfunc.Nbody.Set(body)
+ funcbody()
+
+ xfunc = typecheck(xfunc, ctxStmt)
+ // Need to typecheck the body of the just-generated wrapper.
+ // typecheckslice() requires that Curfn is set when processing an ORETURN.
+ Curfn = xfunc
+ typecheckslice(xfunc.Nbody.Slice(), ctxStmt)
+ sym.Def = asTypesNode(xfunc)
+ xtop = append(xtop, xfunc)
+ Curfn = savecurfn
+ lineno = saveLineNo
+
+ return xfunc
+}
+
+// partialCallType returns the struct type used to hold all the information
+// needed in the closure for n (n must be a OCALLPART node).
+// The address of a variable of the returned type can be cast to a func.
+func partialCallType(n *Node) *types.Type {
+ t := tostruct([]*Node{
+ namedfield("F", types.Types[TUINTPTR]),
+ namedfield("R", n.Left.Type),
+ })
+ t.SetNoalg(true)
+ return t
+}
+
+func walkpartialcall(n *Node, init *Nodes) *Node {
+ // Create closure in the form of a composite literal.
+ // For x.M with receiver (x) type T, the generated code looks like:
+ //
+ // clos = &struct{F uintptr; R T}{T.M·f, x}
+ //
+ // Like walkclosure above.
+
+ if n.Left.Type.IsInterface() {
+ // Trigger panic for method on nil interface now.
+ // Otherwise it happens in the wrapper and is confusing.
+ n.Left = cheapexpr(n.Left, init)
+ n.Left = walkexpr(n.Left, nil)
+
+ tab := nod(OITAB, n.Left, nil)
+ tab = typecheck(tab, ctxExpr)
+
+ c := nod(OCHECKNIL, tab, nil)
+ c.SetTypecheck(1)
+ init.Append(c)
+ }
+
+ typ := partialCallType(n)
+
+ clos := nod(OCOMPLIT, nil, typenod(typ))
+ clos.Esc = n.Esc
+ clos.List.Set2(nod(OCFUNC, n.Func.Nname, nil), n.Left)
+
+ clos = nod(OADDR, clos, nil)
+ clos.Esc = n.Esc
+
+ // Force type conversion from *struct to the func type.
+ clos = convnop(clos, n.Type)
+
+ // non-escaping temp to use, if any.
+ if x := prealloc[n]; x != nil {
+ if !types.Identical(typ, x.Type) {
+ panic("partial call type does not match order's assigned type")
+ }
+ clos.Left.Right = x
+ delete(prealloc, n)
+ }
+
+ return walkexpr(clos, init)
+}
+
+// callpartMethod returns the *types.Field representing the method
+// referenced by method value n.
+func callpartMethod(n *Node) *types.Field {
+ if n.Op != OCALLPART {
+ Fatalf("expected OCALLPART, got %v", n)
+ }
+
+ // TODO(mdempsky): Optimize this. If necessary,
+ // makepartialcall could save m for us somewhere.
+ var m *types.Field
+ if lookdot0(n.Right.Sym, n.Left.Type, &m, false) != 1 {
+ Fatalf("failed to find field for OCALLPART")
+ }
+
+ return m
+}
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
new file mode 100644
index 0000000..b92c8d6
--- /dev/null
+++ b/src/cmd/compile/internal/gc/const.go
@@ -0,0 +1,1323 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "fmt"
+ "math/big"
+ "strings"
+)
+
+// Ctype describes the constant kind of an "ideal" (untyped) constant.
+type Ctype uint8
+
+const (
+ CTxxx Ctype = iota
+
+ CTINT
+ CTRUNE
+ CTFLT
+ CTCPLX
+ CTSTR
+ CTBOOL
+ CTNIL
+)
+
+type Val struct {
+ // U contains one of:
+ // bool bool when Ctype() == CTBOOL
+ // *Mpint int when Ctype() == CTINT, rune when Ctype() == CTRUNE
+ // *Mpflt float when Ctype() == CTFLT
+ // *Mpcplx pair of floats when Ctype() == CTCPLX
+ // string string when Ctype() == CTSTR
+ // *Nilval when Ctype() == CTNIL
+ U interface{}
+}
+
+func (v Val) Ctype() Ctype {
+ switch x := v.U.(type) {
+ default:
+ Fatalf("unexpected Ctype for %T", v.U)
+ panic("unreachable")
+ case nil:
+ return CTxxx
+ case *NilVal:
+ return CTNIL
+ case bool:
+ return CTBOOL
+ case *Mpint:
+ if x.Rune {
+ return CTRUNE
+ }
+ return CTINT
+ case *Mpflt:
+ return CTFLT
+ case *Mpcplx:
+ return CTCPLX
+ case string:
+ return CTSTR
+ }
+}
+
+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("unreachable")
+ 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
+ }
+}
+
+// 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("unreachable")
+ 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())
+ }
+}
+
+type NilVal struct{}
+
+// Int64Val returns n as an int64.
+// n must be an integer or rune constant.
+func (n *Node) Int64Val() int64 {
+ if !Isconst(n, CTINT) {
+ Fatalf("Int64Val(%v)", n)
+ }
+ return n.Val().U.(*Mpint).Int64()
+}
+
+// CanInt64 reports whether it is safe to call Int64Val() on n.
+func (n *Node) CanInt64() bool {
+ if !Isconst(n, CTINT) {
+ return false
+ }
+
+ // if the value inside n cannot be represented as an int64, the
+ // return value of Int64 is undefined
+ return n.Val().U.(*Mpint).CmpInt64(n.Int64Val()) == 0
+}
+
+// BoolVal returns n as a bool.
+// n must be a boolean constant.
+func (n *Node) BoolVal() bool {
+ if !Isconst(n, CTBOOL) {
+ Fatalf("BoolVal(%v)", n)
+ }
+ return n.Val().U.(bool)
+}
+
+// StringVal returns the value of a literal string Node as a string.
+// n must be a string constant.
+func (n *Node) StringVal() string {
+ if !Isconst(n, CTSTR) {
+ Fatalf("StringVal(%v)", n)
+ }
+ return n.Val().U.(string)
+}
+
+// truncate float literal fv to 32-bit or 64-bit precision
+// according to type; return truncated value.
+func truncfltlit(oldv *Mpflt, t *types.Type) *Mpflt {
+ if t == nil {
+ return oldv
+ }
+
+ if overflow(Val{oldv}, t) {
+ // If there was overflow, simply continuing would set the
+ // value to Inf which in turn would lead to spurious follow-on
+ // errors. Avoid this by returning the existing value.
+ return oldv
+ }
+
+ fv := newMpflt()
+
+ // convert large precision literal floating
+ // into limited precision (float64 or float32)
+ switch t.Etype {
+ case types.TFLOAT32:
+ fv.SetFloat64(oldv.Float32())
+ case types.TFLOAT64:
+ fv.SetFloat64(oldv.Float64())
+ default:
+ Fatalf("truncfltlit: unexpected Etype %v", t.Etype)
+ }
+
+ return fv
+}
+
+// truncate Real and Imag parts of Mpcplx to 32-bit or 64-bit
+// precision, according to type; return truncated value. In case of
+// overflow, calls yyerror but does not truncate the input value.
+func trunccmplxlit(oldv *Mpcplx, t *types.Type) *Mpcplx {
+ if t == nil {
+ return oldv
+ }
+
+ if overflow(Val{oldv}, t) {
+ // If there was overflow, simply continuing would set the
+ // value to Inf which in turn would lead to spurious follow-on
+ // errors. Avoid this by returning the existing value.
+ return oldv
+ }
+
+ cv := newMpcmplx()
+
+ switch t.Etype {
+ case types.TCOMPLEX64:
+ cv.Real.SetFloat64(oldv.Real.Float32())
+ cv.Imag.SetFloat64(oldv.Imag.Float32())
+ case types.TCOMPLEX128:
+ cv.Real.SetFloat64(oldv.Real.Float64())
+ cv.Imag.SetFloat64(oldv.Imag.Float64())
+ default:
+ Fatalf("trunccplxlit: unexpected Etype %v", t.Etype)
+ }
+
+ return cv
+}
+
+// TODO(mdempsky): Replace these with better APIs.
+func convlit(n *Node, t *types.Type) *Node { return convlit1(n, t, false, nil) }
+func defaultlit(n *Node, t *types.Type) *Node { return convlit1(n, t, false, nil) }
+
+// convlit1 converts an untyped expression n to type t. If n already
+// has a type, convlit1 has no effect.
+//
+// For explicit conversions, t must be non-nil, and integer-to-string
+// conversions are allowed.
+//
+// For implicit conversions (e.g., assignments), t may be nil; if so,
+// n is converted to its default type.
+//
+// If there's an error converting n to t, context is used in the error
+// message.
+func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Node {
+ if explicit && t == nil {
+ Fatalf("explicit conversion missing type")
+ }
+ if t != nil && t.IsUntyped() {
+ Fatalf("bad conversion to untyped: %v", t)
+ }
+
+ if n == nil || n.Type == nil {
+ // Allow sloppy callers.
+ return n
+ }
+ if !n.Type.IsUntyped() {
+ // Already typed; nothing to do.
+ return n
+ }
+
+ if n.Op == OLITERAL {
+ // Can't always set n.Type directly on OLITERAL nodes.
+ // See discussion on CL 20813.
+ n = n.rawcopy()
+ }
+
+ // Nil is technically not a constant, so handle it specially.
+ if n.Type.Etype == TNIL {
+ if t == nil {
+ yyerror("use of untyped nil")
+ n.SetDiag(true)
+ n.Type = nil
+ return n
+ }
+
+ if !t.HasNil() {
+ // Leave for caller to handle.
+ return n
+ }
+
+ n.Type = t
+ return n
+ }
+
+ if t == nil || !okforconst[t.Etype] {
+ t = defaultType(n.Type)
+ }
+
+ switch n.Op {
+ default:
+ Fatalf("unexpected untyped expression: %v", n)
+
+ case OLITERAL:
+ v := convertVal(n.Val(), t, explicit)
+ if v.U == nil {
+ break
+ }
+ n.SetVal(v)
+ n.Type = t
+ return n
+
+ case OPLUS, ONEG, OBITNOT, ONOT, OREAL, OIMAG:
+ ot := operandType(n.Op, t)
+ if ot == nil {
+ n = defaultlit(n, nil)
+ break
+ }
+
+ n.Left = convlit(n.Left, ot)
+ if n.Left.Type == nil {
+ n.Type = nil
+ return n
+ }
+ n.Type = t
+ return n
+
+ case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND, OCOMPLEX:
+ ot := operandType(n.Op, t)
+ if ot == nil {
+ n = defaultlit(n, nil)
+ break
+ }
+
+ n.Left = convlit(n.Left, ot)
+ n.Right = convlit(n.Right, ot)
+ if n.Left.Type == nil || n.Right.Type == nil {
+ n.Type = nil
+ return n
+ }
+ if !types.Identical(n.Left.Type, n.Right.Type) {
+ yyerror("invalid operation: %v (mismatched types %v and %v)", n, n.Left.Type, n.Right.Type)
+ n.Type = nil
+ return n
+ }
+
+ n.Type = t
+ return n
+
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
+ if !t.IsBoolean() {
+ break
+ }
+ n.Type = t
+ return n
+
+ case OLSH, ORSH:
+ n.Left = convlit1(n.Left, t, explicit, nil)
+ n.Type = n.Left.Type
+ if n.Type != nil && !n.Type.IsInteger() {
+ yyerror("invalid operation: %v (shift of type %v)", n, n.Type)
+ n.Type = nil
+ }
+ return n
+ }
+
+ if !n.Diag() {
+ if !t.Broke() {
+ if explicit {
+ yyerror("cannot convert %L to type %v", n, t)
+ } else if context != nil {
+ yyerror("cannot use %L as type %v in %s", n, t, context())
+ } else {
+ yyerror("cannot use %L as type %v", n, t)
+ }
+ }
+ n.SetDiag(true)
+ }
+ n.Type = nil
+ return n
+}
+
+func operandType(op Op, t *types.Type) *types.Type {
+ switch op {
+ case OCOMPLEX:
+ if t.IsComplex() {
+ return floatForComplex(t)
+ }
+ case OREAL, OIMAG:
+ if t.IsFloat() {
+ return complexForFloat(t)
+ }
+ default:
+ if okfor[op][t.Etype] {
+ return t
+ }
+ }
+ return nil
+}
+
+// convertVal converts v into a representation appropriate for t. If
+// no such representation exists, it returns Val{} instead.
+//
+// If explicit is true, then conversions from integer to string are
+// also allowed.
+func convertVal(v Val, t *types.Type, explicit bool) Val {
+ switch ct := v.Ctype(); ct {
+ case CTBOOL:
+ if t.IsBoolean() {
+ return v
+ }
+
+ case CTSTR:
+ if t.IsString() {
+ return v
+ }
+
+ case CTINT, CTRUNE:
+ if explicit && t.IsString() {
+ return tostr(v)
+ }
+ fallthrough
+ case CTFLT, CTCPLX:
+ switch {
+ case t.IsInteger():
+ v = toint(v)
+ overflow(v, t)
+ return v
+ case t.IsFloat():
+ v = toflt(v)
+ v = Val{truncfltlit(v.U.(*Mpflt), t)}
+ return v
+ case t.IsComplex():
+ v = tocplx(v)
+ v = Val{trunccmplxlit(v.U.(*Mpcplx), t)}
+ return v
+ }
+ }
+
+ return Val{}
+}
+
+func tocplx(v Val) Val {
+ switch u := v.U.(type) {
+ case *Mpint:
+ c := newMpcmplx()
+ c.Real.SetInt(u)
+ c.Imag.SetFloat64(0.0)
+ v.U = c
+
+ case *Mpflt:
+ c := newMpcmplx()
+ c.Real.Set(u)
+ c.Imag.SetFloat64(0.0)
+ v.U = c
+ }
+
+ return v
+}
+
+func toflt(v Val) Val {
+ switch u := v.U.(type) {
+ case *Mpint:
+ f := newMpflt()
+ f.SetInt(u)
+ v.U = f
+
+ case *Mpcplx:
+ f := newMpflt()
+ f.Set(&u.Real)
+ if u.Imag.CmpFloat64(0) != 0 {
+ yyerror("constant %v truncated to real", u.GoString())
+ }
+ v.U = f
+ }
+
+ return v
+}
+
+func toint(v Val) Val {
+ switch u := v.U.(type) {
+ case *Mpint:
+ if u.Rune {
+ i := new(Mpint)
+ i.Set(u)
+ v.U = i
+ }
+
+ case *Mpflt:
+ i := new(Mpint)
+ if !i.SetFloat(u) {
+ if i.checkOverflow(0) {
+ yyerror("integer too large")
+ } else {
+ // The value of u cannot be represented as an integer;
+ // so we need to print an error message.
+ // Unfortunately some float values cannot be
+ // reasonably formatted for inclusion in an error
+ // message (example: 1 + 1e-100), so first we try to
+ // format the float; if the truncation resulted in
+ // something that looks like an integer we omit the
+ // value from the error message.
+ // (See issue #11371).
+ var t big.Float
+ t.Parse(u.GoString(), 10)
+ if t.IsInt() {
+ yyerror("constant truncated to integer")
+ } else {
+ yyerror("constant %v truncated to integer", u.GoString())
+ }
+ }
+ }
+ v.U = i
+
+ case *Mpcplx:
+ i := new(Mpint)
+ if !i.SetFloat(&u.Real) || u.Imag.CmpFloat64(0) != 0 {
+ yyerror("constant %v truncated to integer", u.GoString())
+ }
+
+ v.U = i
+ }
+
+ return v
+}
+
+func doesoverflow(v Val, t *types.Type) bool {
+ switch u := v.U.(type) {
+ case *Mpint:
+ if !t.IsInteger() {
+ Fatalf("overflow: %v integer constant", t)
+ }
+ return u.Cmp(minintval[t.Etype]) < 0 || u.Cmp(maxintval[t.Etype]) > 0
+
+ case *Mpflt:
+ if !t.IsFloat() {
+ Fatalf("overflow: %v floating-point constant", t)
+ }
+ return u.Cmp(minfltval[t.Etype]) <= 0 || u.Cmp(maxfltval[t.Etype]) >= 0
+
+ case *Mpcplx:
+ if !t.IsComplex() {
+ Fatalf("overflow: %v complex constant", t)
+ }
+ return u.Real.Cmp(minfltval[t.Etype]) <= 0 || u.Real.Cmp(maxfltval[t.Etype]) >= 0 ||
+ u.Imag.Cmp(minfltval[t.Etype]) <= 0 || u.Imag.Cmp(maxfltval[t.Etype]) >= 0
+ }
+
+ return false
+}
+
+func overflow(v Val, t *types.Type) bool {
+ // v has already been converted
+ // to appropriate form for t.
+ if t == nil || t.Etype == TIDEAL {
+ return false
+ }
+
+ // Only uintptrs may be converted to pointers, which cannot overflow.
+ if t.IsPtr() || t.IsUnsafePtr() {
+ return false
+ }
+
+ if doesoverflow(v, t) {
+ yyerror("constant %v overflows %v", v, t)
+ return true
+ }
+
+ return false
+
+}
+
+func tostr(v Val) Val {
+ switch u := v.U.(type) {
+ case *Mpint:
+ var r rune = 0xFFFD
+ if u.Cmp(minintval[TINT32]) >= 0 && u.Cmp(maxintval[TINT32]) <= 0 {
+ r = rune(u.Int64())
+ }
+ v.U = string(r)
+ }
+
+ return v
+}
+
+func consttype(n *Node) Ctype {
+ if n == nil || n.Op != OLITERAL {
+ return CTxxx
+ }
+ return n.Val().Ctype()
+}
+
+func Isconst(n *Node, ct Ctype) bool {
+ t := consttype(n)
+
+ // If the caller is asking for CTINT, allow CTRUNE too.
+ // Makes life easier for back ends.
+ return t == ct || (ct == CTINT && t == CTRUNE)
+}
+
+// evconst rewrites constant expressions into OLITERAL nodes.
+func evconst(n *Node) {
+ nl, nr := n.Left, n.Right
+
+ // Pick off just the opcodes that can be constant evaluated.
+ switch op := n.Op; op {
+ case OPLUS, ONEG, OBITNOT, ONOT:
+ if nl.Op == OLITERAL {
+ setconst(n, unaryOp(op, nl.Val(), n.Type))
+ }
+
+ case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ setconst(n, binaryOp(nl.Val(), op, nr.Val()))
+ }
+
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ setboolconst(n, compareOp(nl.Val(), op, nr.Val()))
+ }
+
+ case OLSH, ORSH:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ setconst(n, shiftOp(nl.Val(), op, nr.Val()))
+ }
+
+ case OCONV, ORUNESTR:
+ if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
+ setconst(n, convertVal(nl.Val(), n.Type, true))
+ }
+
+ case OCONVNOP:
+ if okforconst[n.Type.Etype] && nl.Op == OLITERAL {
+ // set so n.Orig gets OCONV instead of OCONVNOP
+ n.Op = OCONV
+ setconst(n, nl.Val())
+ }
+
+ case OADDSTR:
+ // Merge adjacent constants in the argument list.
+ s := n.List.Slice()
+ for i1 := 0; i1 < len(s); i1++ {
+ if Isconst(s[i1], CTSTR) && i1+1 < len(s) && Isconst(s[i1+1], CTSTR) {
+ // merge from i1 up to but not including i2
+ var strs []string
+ i2 := i1
+ for i2 < len(s) && Isconst(s[i2], CTSTR) {
+ strs = append(strs, s[i2].StringVal())
+ i2++
+ }
+
+ nl := *s[i1]
+ nl.Orig = &nl
+ nl.SetVal(Val{strings.Join(strs, "")})
+ s[i1] = &nl
+ s = append(s[:i1+1], s[i2:]...)
+ }
+ }
+
+ if len(s) == 1 && Isconst(s[0], CTSTR) {
+ n.Op = OLITERAL
+ n.SetVal(s[0].Val())
+ } else {
+ n.List.Set(s)
+ }
+
+ case OCAP, OLEN:
+ switch nl.Type.Etype {
+ case TSTRING:
+ if Isconst(nl, CTSTR) {
+ setintconst(n, int64(len(nl.StringVal())))
+ }
+ case TARRAY:
+ if !hascallchan(nl) {
+ setintconst(n, nl.Type.NumElem())
+ }
+ }
+
+ case OALIGNOF, OOFFSETOF, OSIZEOF:
+ setintconst(n, evalunsafe(n))
+
+ case OREAL, OIMAG:
+ if nl.Op == OLITERAL {
+ var re, im *Mpflt
+ switch u := nl.Val().U.(type) {
+ case *Mpint:
+ re = newMpflt()
+ re.SetInt(u)
+ // im = 0
+ case *Mpflt:
+ re = u
+ // im = 0
+ case *Mpcplx:
+ re = &u.Real
+ im = &u.Imag
+ default:
+ Fatalf("impossible")
+ }
+ if n.Op == OIMAG {
+ if im == nil {
+ im = newMpflt()
+ }
+ re = im
+ }
+ setconst(n, Val{re})
+ }
+
+ case OCOMPLEX:
+ if nl.Op == OLITERAL && nr.Op == OLITERAL {
+ // make it a complex literal
+ c := newMpcmplx()
+ c.Real.Set(toflt(nl.Val()).U.(*Mpflt))
+ c.Imag.Set(toflt(nr.Val()).U.(*Mpflt))
+ setconst(n, Val{c})
+ }
+ }
+}
+
+func match(x, y Val) (Val, Val) {
+ switch {
+ case x.Ctype() == CTCPLX || y.Ctype() == CTCPLX:
+ return tocplx(x), tocplx(y)
+ case x.Ctype() == CTFLT || y.Ctype() == CTFLT:
+ return toflt(x), toflt(y)
+ }
+
+ // Mixed int/rune are fine.
+ return x, y
+}
+
+func compareOp(x Val, op Op, y Val) bool {
+ x, y = match(x, y)
+
+ switch x.Ctype() {
+ case CTBOOL:
+ x, y := x.U.(bool), y.U.(bool)
+ switch op {
+ case OEQ:
+ return x == y
+ case ONE:
+ return x != y
+ }
+
+ case CTINT, CTRUNE:
+ x, y := x.U.(*Mpint), y.U.(*Mpint)
+ return cmpZero(x.Cmp(y), op)
+
+ case CTFLT:
+ x, y := x.U.(*Mpflt), y.U.(*Mpflt)
+ return cmpZero(x.Cmp(y), op)
+
+ case CTCPLX:
+ x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
+ eq := x.Real.Cmp(&y.Real) == 0 && x.Imag.Cmp(&y.Imag) == 0
+ switch op {
+ case OEQ:
+ return eq
+ case ONE:
+ return !eq
+ }
+
+ case CTSTR:
+ x, y := x.U.(string), y.U.(string)
+ switch op {
+ case OEQ:
+ return x == y
+ case ONE:
+ return x != y
+ case OLT:
+ return x < y
+ case OLE:
+ return x <= y
+ case OGT:
+ return x > y
+ case OGE:
+ return x >= y
+ }
+ }
+
+ Fatalf("compareOp: bad comparison: %v %v %v", x, op, y)
+ panic("unreachable")
+}
+
+func cmpZero(x int, op Op) bool {
+ switch op {
+ case OEQ:
+ return x == 0
+ case ONE:
+ return x != 0
+ case OLT:
+ return x < 0
+ case OLE:
+ return x <= 0
+ case OGT:
+ return x > 0
+ case OGE:
+ return x >= 0
+ }
+
+ Fatalf("cmpZero: want comparison operator, got %v", op)
+ panic("unreachable")
+}
+
+func binaryOp(x Val, op Op, y Val) Val {
+ x, y = match(x, y)
+
+Outer:
+ switch x.Ctype() {
+ case CTBOOL:
+ x, y := x.U.(bool), y.U.(bool)
+ switch op {
+ case OANDAND:
+ return Val{U: x && y}
+ case OOROR:
+ return Val{U: x || y}
+ }
+
+ case CTINT, CTRUNE:
+ x, y := x.U.(*Mpint), y.U.(*Mpint)
+
+ u := new(Mpint)
+ u.Rune = x.Rune || y.Rune
+ u.Set(x)
+ switch op {
+ case OADD:
+ u.Add(y)
+ case OSUB:
+ u.Sub(y)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if y.CmpInt64(0) == 0 {
+ yyerror("division by zero")
+ return Val{}
+ }
+ u.Quo(y)
+ case OMOD:
+ if y.CmpInt64(0) == 0 {
+ yyerror("division by zero")
+ return Val{}
+ }
+ u.Rem(y)
+ case OOR:
+ u.Or(y)
+ case OAND:
+ u.And(y)
+ case OANDNOT:
+ u.AndNot(y)
+ case OXOR:
+ u.Xor(y)
+ default:
+ break Outer
+ }
+ return Val{U: u}
+
+ case CTFLT:
+ x, y := x.U.(*Mpflt), y.U.(*Mpflt)
+
+ u := newMpflt()
+ u.Set(x)
+ switch op {
+ case OADD:
+ u.Add(y)
+ case OSUB:
+ u.Sub(y)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if y.CmpFloat64(0) == 0 {
+ yyerror("division by zero")
+ return Val{}
+ }
+ u.Quo(y)
+ default:
+ break Outer
+ }
+ return Val{U: u}
+
+ case CTCPLX:
+ x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
+
+ u := newMpcmplx()
+ u.Real.Set(&x.Real)
+ u.Imag.Set(&x.Imag)
+ switch op {
+ case OADD:
+ u.Real.Add(&y.Real)
+ u.Imag.Add(&y.Imag)
+ case OSUB:
+ u.Real.Sub(&y.Real)
+ u.Imag.Sub(&y.Imag)
+ case OMUL:
+ u.Mul(y)
+ case ODIV:
+ if !u.Div(y) {
+ yyerror("complex division by zero")
+ return Val{}
+ }
+ default:
+ break Outer
+ }
+ return Val{U: u}
+ }
+
+ Fatalf("binaryOp: bad operation: %v %v %v", x, op, y)
+ panic("unreachable")
+}
+
+func unaryOp(op Op, x Val, t *types.Type) Val {
+ switch op {
+ case OPLUS:
+ switch x.Ctype() {
+ case CTINT, CTRUNE, CTFLT, CTCPLX:
+ return x
+ }
+
+ case ONEG:
+ switch x.Ctype() {
+ case CTINT, CTRUNE:
+ x := x.U.(*Mpint)
+ u := new(Mpint)
+ u.Rune = x.Rune
+ u.Set(x)
+ u.Neg()
+ return Val{U: u}
+
+ case CTFLT:
+ x := x.U.(*Mpflt)
+ u := newMpflt()
+ u.Set(x)
+ u.Neg()
+ return Val{U: u}
+
+ case CTCPLX:
+ x := x.U.(*Mpcplx)
+ u := newMpcmplx()
+ u.Real.Set(&x.Real)
+ u.Imag.Set(&x.Imag)
+ u.Real.Neg()
+ u.Imag.Neg()
+ return Val{U: u}
+ }
+
+ case OBITNOT:
+ switch x.Ctype() {
+ case CTINT, CTRUNE:
+ x := x.U.(*Mpint)
+
+ u := new(Mpint)
+ u.Rune = x.Rune
+ if t.IsSigned() || t.IsUntyped() {
+ // Signed values change sign.
+ u.SetInt64(-1)
+ } else {
+ // Unsigned values invert their bits.
+ u.Set(maxintval[t.Etype])
+ }
+ u.Xor(x)
+ return Val{U: u}
+ }
+
+ case ONOT:
+ return Val{U: !x.U.(bool)}
+ }
+
+ Fatalf("unaryOp: bad operation: %v %v", op, x)
+ panic("unreachable")
+}
+
+func shiftOp(x Val, op Op, y Val) Val {
+ if x.Ctype() != CTRUNE {
+ x = toint(x)
+ }
+ y = toint(y)
+
+ u := new(Mpint)
+ u.Set(x.U.(*Mpint))
+ u.Rune = x.U.(*Mpint).Rune
+ switch op {
+ case OLSH:
+ u.Lsh(y.U.(*Mpint))
+ case ORSH:
+ u.Rsh(y.U.(*Mpint))
+ default:
+ Fatalf("shiftOp: bad operator: %v", op)
+ panic("unreachable")
+ }
+ return Val{U: u}
+}
+
+// setconst rewrites n as an OLITERAL with value v.
+func setconst(n *Node, v Val) {
+ // If constant folding failed, mark n as broken and give up.
+ if v.U == nil {
+ n.Type = nil
+ return
+ }
+
+ // Ensure n.Orig still points to a semantically-equivalent
+ // expression after we rewrite n into a constant.
+ if n.Orig == n {
+ n.Orig = n.sepcopy()
+ }
+
+ *n = Node{
+ Op: OLITERAL,
+ Pos: n.Pos,
+ Orig: n.Orig,
+ Type: n.Type,
+ Xoffset: BADWIDTH,
+ }
+ n.SetVal(v)
+ if vt := idealType(v.Ctype()); n.Type.IsUntyped() && n.Type != vt {
+ Fatalf("untyped type mismatch, have: %v, want: %v", n.Type, vt)
+ }
+
+ // Check range.
+ lno := setlineno(n)
+ overflow(v, n.Type)
+ lineno = lno
+
+ if !n.Type.IsUntyped() {
+ switch v.Ctype() {
+ // Truncate precision for non-ideal float.
+ case CTFLT:
+ n.SetVal(Val{truncfltlit(v.U.(*Mpflt), n.Type)})
+ // Truncate precision for non-ideal complex.
+ case CTCPLX:
+ n.SetVal(Val{trunccmplxlit(v.U.(*Mpcplx), n.Type)})
+ }
+ }
+}
+
+func setboolconst(n *Node, v bool) {
+ setconst(n, Val{U: v})
+}
+
+func setintconst(n *Node, v int64) {
+ u := new(Mpint)
+ u.SetInt64(v)
+ setconst(n, Val{u})
+}
+
+// nodlit returns a new untyped constant with value v.
+func nodlit(v Val) *Node {
+ n := nod(OLITERAL, nil, nil)
+ n.SetVal(v)
+ n.Type = idealType(v.Ctype())
+ return n
+}
+
+func idealType(ct Ctype) *types.Type {
+ switch ct {
+ case CTSTR:
+ return types.UntypedString
+ case CTBOOL:
+ return types.UntypedBool
+ case CTINT:
+ return types.UntypedInt
+ case CTRUNE:
+ return types.UntypedRune
+ case CTFLT:
+ return types.UntypedFloat
+ case CTCPLX:
+ return types.UntypedComplex
+ case CTNIL:
+ return types.Types[TNIL]
+ }
+ Fatalf("unexpected Ctype: %v", ct)
+ return nil
+}
+
+// defaultlit on both nodes simultaneously;
+// if they're both ideal going in they better
+// get the same type going out.
+// force means must assign concrete (non-ideal) type.
+// The results of defaultlit2 MUST be assigned back to l and r, e.g.
+// n.Left, n.Right = defaultlit2(n.Left, n.Right, force)
+func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
+ if l.Type == nil || r.Type == nil {
+ return l, r
+ }
+ if !l.Type.IsUntyped() {
+ r = convlit(r, l.Type)
+ return l, r
+ }
+
+ if !r.Type.IsUntyped() {
+ l = convlit(l, r.Type)
+ return l, r
+ }
+
+ if !force {
+ return l, r
+ }
+
+ // Can't mix bool with non-bool, string with non-string, or nil with anything (untyped).
+ if l.Type.IsBoolean() != r.Type.IsBoolean() {
+ return l, r
+ }
+ if l.Type.IsString() != r.Type.IsString() {
+ return l, r
+ }
+ if l.isNil() || r.isNil() {
+ return l, r
+ }
+
+ t := defaultType(mixUntyped(l.Type, r.Type))
+ l = convlit(l, t)
+ r = convlit(r, t)
+ return l, r
+}
+
+func ctype(t *types.Type) Ctype {
+ switch t {
+ case types.UntypedBool:
+ return CTBOOL
+ case types.UntypedString:
+ return CTSTR
+ case types.UntypedInt:
+ return CTINT
+ case types.UntypedRune:
+ return CTRUNE
+ case types.UntypedFloat:
+ return CTFLT
+ case types.UntypedComplex:
+ return CTCPLX
+ }
+ Fatalf("bad type %v", t)
+ panic("unreachable")
+}
+
+func mixUntyped(t1, t2 *types.Type) *types.Type {
+ t := t1
+ if ctype(t2) > ctype(t1) {
+ t = t2
+ }
+ return t
+}
+
+func defaultType(t *types.Type) *types.Type {
+ if !t.IsUntyped() || t.Etype == TNIL {
+ return t
+ }
+
+ switch t {
+ case types.UntypedBool:
+ return types.Types[TBOOL]
+ case types.UntypedString:
+ return types.Types[TSTRING]
+ case types.UntypedInt:
+ return types.Types[TINT]
+ case types.UntypedRune:
+ return types.Runetype
+ case types.UntypedFloat:
+ return types.Types[TFLOAT64]
+ case types.UntypedComplex:
+ return types.Types[TCOMPLEX128]
+ }
+
+ Fatalf("bad type %v", t)
+ return nil
+}
+
+func smallintconst(n *Node) bool {
+ if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
+ switch simtype[n.Type.Etype] {
+ case TINT8,
+ TUINT8,
+ TINT16,
+ TUINT16,
+ TINT32,
+ TUINT32,
+ TBOOL:
+ return true
+
+ case TIDEAL, TINT64, TUINT64, TPTR:
+ v, ok := n.Val().U.(*Mpint)
+ if ok && v.Cmp(minintval[TINT32]) >= 0 && v.Cmp(maxintval[TINT32]) <= 0 {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+// indexconst checks if Node n contains a constant expression
+// representable as a non-negative int and returns its value.
+// If n is not a constant expression, not representable as an
+// integer, or negative, it returns -1. If n is too large, it
+// returns -2.
+func indexconst(n *Node) int64 {
+ if n.Op != OLITERAL {
+ return -1
+ }
+
+ v := toint(n.Val()) // toint returns argument unchanged if not representable as an *Mpint
+ vi, ok := v.U.(*Mpint)
+ if !ok || vi.CmpInt64(0) < 0 {
+ return -1
+ }
+ if vi.Cmp(maxintval[TINT]) > 0 {
+ return -2
+ }
+
+ return vi.Int64()
+}
+
+// isGoConst reports whether n is a Go language constant (as opposed to a
+// compile-time constant).
+//
+// Expressions derived from nil, like string([]byte(nil)), while they
+// may be known at compile time, are not Go language constants.
+func (n *Node) isGoConst() bool {
+ return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
+}
+
+func hascallchan(n *Node) bool {
+ if n == nil {
+ return false
+ }
+ switch n.Op {
+ case OAPPEND,
+ OCALL,
+ OCALLFUNC,
+ OCALLINTER,
+ OCALLMETH,
+ OCAP,
+ OCLOSE,
+ OCOMPLEX,
+ OCOPY,
+ ODELETE,
+ OIMAG,
+ OLEN,
+ OMAKE,
+ ONEW,
+ OPANIC,
+ OPRINT,
+ OPRINTN,
+ OREAL,
+ ORECOVER,
+ ORECV:
+ return true
+ }
+
+ if hascallchan(n.Left) || hascallchan(n.Right) {
+ return true
+ }
+ for _, n1 := range n.List.Slice() {
+ if hascallchan(n1) {
+ return true
+ }
+ }
+ for _, n2 := range n.Rlist.Slice() {
+ if hascallchan(n2) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// A constSet represents a set of Go constant expressions.
+type constSet struct {
+ m map[constSetKey]src.XPos
+}
+
+type constSetKey struct {
+ typ *types.Type
+ val interface{}
+}
+
+// add adds constant expression n to s. If a constant expression of
+// equal value and identical type has already been added, then add
+// reports an error about the duplicate value.
+//
+// pos provides position information for where expression n occurred
+// (in case n does not have its own position information). what and
+// where are used in the error message.
+//
+// n must not be an untyped constant.
+func (s *constSet) add(pos src.XPos, n *Node, what, where string) {
+ if n.Op == OCONVIFACE && n.Implicit() {
+ n = n.Left
+ }
+
+ if !n.isGoConst() {
+ return
+ }
+ if n.Type.IsUntyped() {
+ Fatalf("%v is untyped", n)
+ }
+
+ // Consts are only duplicates if they have the same value and
+ // identical types.
+ //
+ // In general, we have to use types.Identical to test type
+ // identity, because == gives false negatives for anonymous
+ // types and the byte/uint8 and rune/int32 builtin type
+ // aliases. However, this is not a problem here, because
+ // constant expressions are always untyped or have a named
+ // type, and we explicitly handle the builtin type aliases
+ // below.
+ //
+ // This approach may need to be revisited though if we fix
+ // #21866 by treating all type aliases like byte/uint8 and
+ // rune/int32.
+
+ typ := n.Type
+ switch typ {
+ case types.Bytetype:
+ typ = types.Types[TUINT8]
+ case types.Runetype:
+ typ = types.Types[TINT32]
+ }
+ k := constSetKey{typ, n.Val().Interface()}
+
+ if hasUniquePos(n) {
+ pos = n.Pos
+ }
+
+ if s.m == nil {
+ s.m = make(map[constSetKey]src.XPos)
+ }
+
+ if prevPos, isDup := s.m[k]; isDup {
+ yyerrorl(pos, "duplicate %s %s in %s\n\tprevious %s at %v",
+ what, nodeAndVal(n), where,
+ what, linestr(prevPos))
+ } else {
+ s.m[k] = pos
+ }
+}
+
+// nodeAndVal reports both an expression and its constant value, if
+// the latter is non-obvious.
+//
+// TODO(mdempsky): This could probably be a fmt.go flag.
+func nodeAndVal(n *Node) string {
+ show := n.String()
+ val := n.Val().Interface()
+ if s := fmt.Sprintf("%#v", val); show != s {
+ show += " (value " + s + ")"
+ }
+ return show
+}
diff --git a/src/cmd/compile/internal/gc/constFold_test.go b/src/cmd/compile/internal/gc/constFold_test.go
new file mode 100644
index 0000000..59f905d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/constFold_test.go
@@ -0,0 +1,18111 @@
+// run
+// Code generated by gen/constFoldGen.go. DO NOT EDIT.
+
+package gc
+
+import "testing"
+
+func TestConstFolduint64add(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967296 {
+ t.Errorf("0 %s 4294967296 = %d, want 4294967296", "+", r)
+ }
+ y = 18446744073709551615
+ r = x + y
+ if r != 18446744073709551615 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 18446744073709551615", "+", r)
+ }
+ x = 1
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967297 {
+ t.Errorf("1 %s 4294967296 = %d, want 4294967297", "+", r)
+ }
+ y = 18446744073709551615
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "+", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x + y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 4294967297 {
+ t.Errorf("4294967296 %s 1 = %d, want 4294967297", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 8589934592", "+", r)
+ }
+ y = 18446744073709551615
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 4294967295", "+", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x + y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 0", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 4294967295", "+", r)
+ }
+ y = 18446744073709551615
+ r = x + y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 18446744073709551614", "+", r)
+ }
+}
+func TestConstFolduint64sub(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 18446744073709551615 {
+ t.Errorf("0 %s 1 = %d, want 18446744073709551615", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 18446744069414584320 {
+ t.Errorf("0 %s 4294967296 = %d, want 18446744069414584320", "-", r)
+ }
+ y = 18446744073709551615
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 1", "-", r)
+ }
+ x = 1
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 18446744069414584321 {
+ t.Errorf("1 %s 4294967296 = %d, want 18446744069414584321", "-", r)
+ }
+ y = 18446744073709551615
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 2", "-", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x - y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("4294967296 %s 1 = %d, want 4294967295", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "-", r)
+ }
+ y = 18446744073709551615
+ r = x - y
+ if r != 4294967297 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 4294967297", "-", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x - y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 18446744069414584319 {
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 18446744069414584319", "-", r)
+ }
+ y = 18446744073709551615
+ r = x - y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 0", "-", r)
+ }
+}
+func TestConstFolduint64div(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "/", r)
+ }
+ y = 18446744073709551615
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "/", r)
+ }
+ x = 1
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "/", r)
+ }
+ y = 18446744073709551615
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "/", r)
+ }
+ x = 4294967296
+ y = 1
+ r = x / y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 1 = %d, want 4294967296", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 1 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 1", "/", r)
+ }
+ y = 18446744073709551615
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", "/", r)
+ }
+ x = 18446744073709551615
+ y = 1
+ r = x / y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551615", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 4294967295 {
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 4294967295", "/", r)
+ }
+ y = 18446744073709551615
+ r = x / y
+ if r != 1 {
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 1", "/", r)
+ }
+}
+func TestConstFolduint64mul(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "*", r)
+ }
+ y = 18446744073709551615
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "*", r)
+ }
+ x = 1
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("1 %s 4294967296 = %d, want 4294967296", "*", r)
+ }
+ y = 18446744073709551615
+ r = x * y
+ if r != 18446744073709551615 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 18446744073709551615", "*", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 1 = %d, want 4294967296", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "*", r)
+ }
+ y = 18446744073709551615
+ r = x * y
+ if r != 18446744069414584320 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 18446744069414584320", "*", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551615", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 18446744069414584320 {
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 18446744069414584320", "*", r)
+ }
+ y = 18446744073709551615
+ r = x * y
+ if r != 1 {
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 1", "*", r)
+ }
+}
+func TestConstFolduint64mod(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "%", r)
+ }
+ y = 18446744073709551615
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "%", r)
+ }
+ x = 1
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 4294967296 = %d, want 1", "%", r)
+ }
+ y = 18446744073709551615
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 1", "%", r)
+ }
+ x = 4294967296
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "%", r)
+ }
+ y = 18446744073709551615
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 4294967296", "%", r)
+ }
+ x = 18446744073709551615
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 4294967295 {
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 4294967295", "%", r)
+ }
+ y = 18446744073709551615
+ r = x % y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 0", "%", r)
+ }
+}
+func TestConstFoldint64add(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x + y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 0", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != 1 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want 1", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 9223372032559808512 {
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want 9223372032559808512", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("-9223372036854775808 %s -1 = %d, want 9223372036854775807", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -9223372036854775807", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != -9223372032559808512 {
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want -9223372032559808512", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -2 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want -2", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want -1", "+", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x + y
+ if r != 1 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want 1", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 2", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 9223372032559808513 {
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want 9223372032559808513", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775807 %s -1 = %d, want -9223372036854775808", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -9223372036854775806 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -9223372036854775806", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != -9223372032559808511 {
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want -9223372032559808511", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want -1", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want 0", "+", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x + y
+ if r != 9223372032559808512 {
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want 9223372032559808512", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != 9223372032559808513 {
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want 9223372032559808513", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 %s -4294967296 = %d, want -8589934592", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -4294967297 {
+ t.Errorf("-4294967296 %s -1 = %d, want -4294967297", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -4294967295 {
+ t.Errorf("-4294967296 %s 1 = %d, want -4294967295", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 4294967296 = %d, want 0", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != 9223372032559808510 {
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want 9223372032559808510", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != 9223372032559808511 {
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want 9223372032559808511", "+", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("-1 %s -9223372036854775808 = %d, want 9223372036854775807", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("-1 %s -9223372036854775807 = %d, want -9223372036854775808", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != -4294967297 {
+ t.Errorf("-1 %s -4294967296 = %d, want -4294967297", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2 {
+ t.Errorf("-1 %s -1 = %d, want -2", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("-1 %s 1 = %d, want 0", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("-1 %s 4294967296 = %d, want 4294967295", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != 9223372036854775805 {
+ t.Errorf("-1 %s 9223372036854775806 = %d, want 9223372036854775805", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != 9223372036854775806 {
+ t.Errorf("-1 %s 9223372036854775807 = %d, want 9223372036854775806", "+", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("0 %s -9223372036854775808 = %d, want -9223372036854775808", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -9223372036854775807 {
+ t.Errorf("0 %s -9223372036854775807 = %d, want -9223372036854775807", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != -4294967296 {
+ t.Errorf("0 %s -4294967296 = %d, want -4294967296", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -1 {
+ t.Errorf("0 %s -1 = %d, want -1", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967296 {
+ t.Errorf("0 %s 4294967296 = %d, want 4294967296", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != 9223372036854775806 {
+ t.Errorf("0 %s 9223372036854775806 = %d, want 9223372036854775806", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("0 %s 9223372036854775807 = %d, want 9223372036854775807", "+", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x + y
+ if r != -9223372036854775807 {
+ t.Errorf("1 %s -9223372036854775808 = %d, want -9223372036854775807", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -9223372036854775806 {
+ t.Errorf("1 %s -9223372036854775807 = %d, want -9223372036854775806", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != -4294967295 {
+ t.Errorf("1 %s -4294967296 = %d, want -4294967295", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 %s -1 = %d, want 0", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967297 {
+ t.Errorf("1 %s 4294967296 = %d, want 4294967297", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("1 %s 9223372036854775806 = %d, want 9223372036854775807", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("1 %s 9223372036854775807 = %d, want -9223372036854775808", "+", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x + y
+ if r != -9223372032559808512 {
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want -9223372032559808512", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -9223372032559808511 {
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want -9223372032559808511", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 0 {
+ t.Errorf("4294967296 %s -4294967296 = %d, want 0", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("4294967296 %s -1 = %d, want 4294967295", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 4294967297 {
+ t.Errorf("4294967296 %s 1 = %d, want 4294967297", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 8589934592", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -9223372032559808514 {
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want -9223372032559808514", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -9223372032559808513 {
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want -9223372032559808513", "+", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x + y
+ if r != -2 {
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want -2", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -1 {
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want -1", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 9223372032559808510 {
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want 9223372032559808510", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 9223372036854775805 {
+ t.Errorf("9223372036854775806 %s -1 = %d, want 9223372036854775805", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 9223372036854775807", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != -9223372032559808514 {
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want -9223372032559808514", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -4 {
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want -4", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -3 {
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want -3", "+", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x + y
+ if r != -1 {
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want -1", "+", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want 0", "+", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 9223372032559808511 {
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want 9223372032559808511", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775807 %s -1 = %d, want 9223372036854775806", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want -9223372036854775808", "+", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != -9223372032559808513 {
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want -9223372032559808513", "+", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -3 {
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want -3", "+", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -2 {
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want -2", "+", r)
+ }
+}
+func TestConstFoldint64sub(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x - y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 0", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want -1", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != -9223372032559808512 {
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want -9223372032559808512", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775808 %s -1 = %d, want -9223372036854775807", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 9223372036854775807", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 9223372032559808512 {
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want 9223372032559808512", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 2 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want 2", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != 1 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want 1", "-", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x - y
+ if r != 1 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want 1", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 0", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != -9223372032559808511 {
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want -9223372032559808511", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -9223372036854775806 {
+ t.Errorf("-9223372036854775807 %s -1 = %d, want -9223372036854775806", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -9223372036854775808", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 9223372032559808513 {
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want 9223372032559808513", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 3 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want 3", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want 2", "-", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x - y
+ if r != 9223372032559808512 {
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want 9223372032559808512", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != 9223372032559808511 {
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want 9223372032559808511", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 0 {
+ t.Errorf("-4294967296 %s -4294967296 = %d, want 0", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -4294967295 {
+ t.Errorf("-4294967296 %s -1 = %d, want -4294967295", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -4294967297 {
+ t.Errorf("-4294967296 %s 1 = %d, want -4294967297", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 %s 4294967296 = %d, want -8589934592", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 9223372032559808514 {
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want 9223372032559808514", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != 9223372032559808513 {
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want 9223372032559808513", "-", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("-1 %s -9223372036854775808 = %d, want 9223372036854775807", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != 9223372036854775806 {
+ t.Errorf("-1 %s -9223372036854775807 = %d, want 9223372036854775806", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("-1 %s -4294967296 = %d, want 4294967295", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 0 {
+ t.Errorf("-1 %s -1 = %d, want 0", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != -4294967297 {
+ t.Errorf("-1 %s 4294967296 = %d, want -4294967297", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("-1 %s 9223372036854775806 = %d, want -9223372036854775807", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("-1 %s 9223372036854775807 = %d, want -9223372036854775808", "-", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("0 %s -9223372036854775808 = %d, want -9223372036854775808", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("0 %s -9223372036854775807 = %d, want 9223372036854775807", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 4294967296 {
+ t.Errorf("0 %s -4294967296 = %d, want 4294967296", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 %s -1 = %d, want 1", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -1 {
+ t.Errorf("0 %s 1 = %d, want -1", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != -4294967296 {
+ t.Errorf("0 %s 4294967296 = %d, want -4294967296", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != -9223372036854775806 {
+ t.Errorf("0 %s 9223372036854775806 = %d, want -9223372036854775806", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("0 %s 9223372036854775807 = %d, want -9223372036854775807", "-", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("1 %s -9223372036854775808 = %d, want -9223372036854775807", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("1 %s -9223372036854775807 = %d, want -9223372036854775808", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 4294967297 {
+ t.Errorf("1 %s -4294967296 = %d, want 4294967297", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 %s -1 = %d, want 2", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != -4294967295 {
+ t.Errorf("1 %s 4294967296 = %d, want -4294967295", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != -9223372036854775805 {
+ t.Errorf("1 %s 9223372036854775806 = %d, want -9223372036854775805", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -9223372036854775806 {
+ t.Errorf("1 %s 9223372036854775807 = %d, want -9223372036854775806", "-", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x - y
+ if r != -9223372032559808512 {
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want -9223372032559808512", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -9223372032559808513 {
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want -9223372032559808513", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s -4294967296 = %d, want 8589934592", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 4294967297 {
+ t.Errorf("4294967296 %s -1 = %d, want 4294967297", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("4294967296 %s 1 = %d, want 4294967295", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != -9223372032559808510 {
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want -9223372032559808510", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -9223372032559808511 {
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want -9223372032559808511", "-", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x - y
+ if r != -2 {
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want -2", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -3 {
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want -3", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != -9223372032559808514 {
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want -9223372032559808514", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775806 %s -1 = %d, want 9223372036854775807", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 9223372036854775805 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 9223372036854775805", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 9223372032559808510 {
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 9223372032559808510", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want 0", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -1 {
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want -1", "-", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x - y
+ if r != -1 {
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want -1", "-", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -2 {
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want -2", "-", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != -9223372032559808513 {
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want -9223372032559808513", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("9223372036854775807 %s -1 = %d, want -9223372036854775808", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want 9223372036854775806", "-", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 9223372032559808511 {
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 9223372032559808511", "-", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 1 {
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want 1", "-", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want 0", "-", r)
+ }
+}
+func TestConstFoldint64div(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x / y
+ if r != 1 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 1", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 1 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want 1", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 2147483648 {
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want 2147483648", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s -1 = %d, want -9223372036854775808", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -9223372036854775808", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != -2147483648 {
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want -2147483648", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want -1", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want -1", "/", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want 0", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 1 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 1", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want 2147483647", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s -1 = %d, want 9223372036854775807", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -9223372036854775807", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want -2147483647", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want -1", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want -1", "/", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want 0", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want 0", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 1 {
+ t.Errorf("-4294967296 %s -4294967296 = %d, want 1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 4294967296 {
+ t.Errorf("-4294967296 %s -1 = %d, want 4294967296", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 1 = %d, want -4294967296", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != -1 {
+ t.Errorf("-4294967296 %s 4294967296 = %d, want -1", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want 0", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want 0", "/", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -9223372036854775808 = %d, want 0", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -9223372036854775807 = %d, want 0", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -4294967296 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 1 {
+ t.Errorf("-1 %s -1 = %d, want 1", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s 9223372036854775806 = %d, want 0", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s 9223372036854775807 = %d, want 0", "/", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -9223372036854775808 = %d, want 0", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -9223372036854775807 = %d, want 0", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -4294967296 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 9223372036854775806 = %d, want 0", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 9223372036854775807 = %d, want 0", "/", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -9223372036854775808 = %d, want 0", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -9223372036854775807 = %d, want 0", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -4294967296 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -1 {
+ t.Errorf("1 %s -1 = %d, want -1", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 9223372036854775806 = %d, want 0", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 9223372036854775807 = %d, want 0", "/", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want 0", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want 0", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != -1 {
+ t.Errorf("4294967296 %s -4294967296 = %d, want -1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -4294967296 {
+ t.Errorf("4294967296 %s -1 = %d, want -4294967296", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 1 = %d, want 4294967296", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 1 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 1", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want 0", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want 0", "/", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want 0", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want 0", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want -2147483647", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -9223372036854775806 {
+ t.Errorf("9223372036854775806 %s -1 = %d, want -9223372036854775806", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 9223372036854775806", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 2147483647", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 1 {
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want 1", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want 0", "/", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want 0", "/", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != -1 {
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want -1", "/", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want -2147483647", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -9223372036854775807 {
+ t.Errorf("9223372036854775807 %s -1 = %d, want -9223372036854775807", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want 9223372036854775807", "/", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 2147483647", "/", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 1 {
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want 1", "/", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 1 {
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want 1", "/", r)
+ }
+}
+func TestConstFoldint64mul(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 0", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want -9223372036854775808", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want 0", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s -1 = %d, want -9223372036854775808", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -9223372036854775808", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want 0", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want 0", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want -9223372036854775808", "*", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want -9223372036854775808", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 1 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 1", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want -4294967296", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s -1 = %d, want 9223372036854775807", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -9223372036854775807", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want 4294967296", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 9223372036854775806 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want 9223372036854775806", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want -1", "*", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want 0", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want -4294967296", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("-4294967296 %s -4294967296 = %d, want 0", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("-4294967296 %s -1 = %d, want 4294967296", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 1 = %d, want -4294967296", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 4294967296 = %d, want 0", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 8589934592 {
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want 8589934592", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want 4294967296", "*", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-1 %s -9223372036854775808 = %d, want -9223372036854775808", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 9223372036854775807 {
+ t.Errorf("-1 %s -9223372036854775807 = %d, want 9223372036854775807", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("-1 %s -4294967296 = %d, want 4294967296", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 1 {
+ t.Errorf("-1 %s -1 = %d, want 1", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("-1 %s 4294967296 = %d, want -4294967296", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != -9223372036854775806 {
+ t.Errorf("-1 %s 9223372036854775806 = %d, want -9223372036854775806", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -9223372036854775807 {
+ t.Errorf("-1 %s 9223372036854775807 = %d, want -9223372036854775807", "*", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -9223372036854775808 = %d, want 0", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -9223372036854775807 = %d, want 0", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -4294967296 = %d, want 0", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 9223372036854775806 = %d, want 0", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 9223372036854775807 = %d, want 0", "*", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("1 %s -9223372036854775808 = %d, want -9223372036854775808", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != -9223372036854775807 {
+ t.Errorf("1 %s -9223372036854775807 = %d, want -9223372036854775807", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("1 %s -4294967296 = %d, want -4294967296", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -1 {
+ t.Errorf("1 %s -1 = %d, want -1", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("1 %s 4294967296 = %d, want 4294967296", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 9223372036854775806 {
+ t.Errorf("1 %s 9223372036854775806 = %d, want 9223372036854775806", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != 9223372036854775807 {
+ t.Errorf("1 %s 9223372036854775807 = %d, want 9223372036854775807", "*", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want 0", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want 4294967296", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 %s -4294967296 = %d, want 0", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("4294967296 %s -1 = %d, want -4294967296", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 1 = %d, want 4294967296", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != -8589934592 {
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want -8589934592", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want -4294967296", "*", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want 0", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want 9223372036854775806", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 8589934592 {
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want 8589934592", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -9223372036854775806 {
+ t.Errorf("9223372036854775806 %s -1 = %d, want -9223372036854775806", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 9223372036854775806", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != -8589934592 {
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want -8589934592", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 4 {
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want 4", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want -9223372036854775806", "*", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want -9223372036854775808", "*", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != -1 {
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want -1", "*", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want 4294967296", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -9223372036854775807 {
+ t.Errorf("9223372036854775807 %s -1 = %d, want -9223372036854775807", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want 9223372036854775807", "*", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want -4294967296", "*", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != -9223372036854775806 {
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want -9223372036854775806", "*", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != 1 {
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want 1", "*", r)
+ }
+}
+func TestConstFoldint64mod(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 0", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want -1", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want 0", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != -2 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want -2", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want -1", "%", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x % y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want -9223372036854775807", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 0", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != -4294967295 {
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want -4294967295", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != -4294967295 {
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want -4294967295", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want -1", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want 0", "%", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x % y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want -4294967296", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want -4294967296", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("-4294967296 %s -4294967296 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-4294967296 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 4294967296 = %d, want 0", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want -4294967296", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want -4294967296", "%", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -9223372036854775808 = %d, want -1", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -9223372036854775807 = %d, want -1", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -4294967296 = %d, want -1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967296 = %d, want -1", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s 9223372036854775806 = %d, want -1", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s 9223372036854775807 = %d, want -1", "%", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -9223372036854775808 = %d, want 0", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -9223372036854775807 = %d, want 0", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -4294967296 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 9223372036854775806 = %d, want 0", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 9223372036854775807 = %d, want 0", "%", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -9223372036854775808 = %d, want 1", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -9223372036854775807 = %d, want 1", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -4294967296 = %d, want 1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 4294967296 = %d, want 1", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 9223372036854775806 = %d, want 1", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 9223372036854775807 = %d, want 1", "%", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want 4294967296", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want 4294967296", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 %s -4294967296 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want 4294967296", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want 4294967296", "%", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x % y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want 9223372036854775806", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want 9223372036854775806", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 4294967294 {
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want 4294967294", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 4294967294 {
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 4294967294", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want 0", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want 9223372036854775806", "%", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x % y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want 9223372036854775807", "%", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want 0", "%", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 4294967295 {
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want 4294967295", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 4294967295 {
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 4294967295", "%", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 1 {
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want 1", "%", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want 0", "%", r)
+ }
+}
+func TestConstFolduint32add(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
+ }
+ y = 4294967295
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("0 %s 4294967295 = %d, want 4294967295", "+", r)
+ }
+ x = 1
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
+ }
+ y = 4294967295
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "+", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("4294967295 %s 1 = %d, want 0", "+", r)
+ }
+ y = 4294967295
+ r = x + y
+ if r != 4294967294 {
+ t.Errorf("4294967295 %s 4294967295 = %d, want 4294967294", "+", r)
+ }
+}
+func TestConstFolduint32sub(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("0 %s 1 = %d, want 4294967295", "-", r)
+ }
+ y = 4294967295
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 %s 4294967295 = %d, want 1", "-", r)
+ }
+ x = 1
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
+ }
+ y = 4294967295
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 %s 4294967295 = %d, want 2", "-", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 4294967294 {
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "-", r)
+ }
+ y = 4294967295
+ r = x - y
+ if r != 0 {
+ t.Errorf("4294967295 %s 4294967295 = %d, want 0", "-", r)
+ }
+}
+func TestConstFolduint32div(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
+ }
+ y = 4294967295
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "/", r)
+ }
+ x = 1
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
+ }
+ y = 4294967295
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "/", r)
+ }
+ x = 4294967295
+ y = 1
+ r = x / y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 1 = %d, want 4294967295", "/", r)
+ }
+ y = 4294967295
+ r = x / y
+ if r != 1 {
+ t.Errorf("4294967295 %s 4294967295 = %d, want 1", "/", r)
+ }
+}
+func TestConstFolduint32mul(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
+ }
+ y = 4294967295
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "*", r)
+ }
+ x = 1
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
+ }
+ y = 4294967295
+ r = x * y
+ if r != 4294967295 {
+ t.Errorf("1 %s 4294967295 = %d, want 4294967295", "*", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967295 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 1 = %d, want 4294967295", "*", r)
+ }
+ y = 4294967295
+ r = x * y
+ if r != 1 {
+ t.Errorf("4294967295 %s 4294967295 = %d, want 1", "*", r)
+ }
+}
+func TestConstFolduint32mod(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967295
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "%", r)
+ }
+ x = 1
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967295
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 4294967295 = %d, want 1", "%", r)
+ }
+ x = 4294967295
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967295 %s 1 = %d, want 0", "%", r)
+ }
+ y = 4294967295
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967295 %s 4294967295 = %d, want 0", "%", r)
+ }
+}
+func TestConstFoldint32add(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x + y
+ if r != 0 {
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 0", "+", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != 1 {
+ t.Errorf("-2147483648 %s -2147483647 = %d, want 1", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 2147483647 {
+ t.Errorf("-2147483648 %s -1 = %d, want 2147483647", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -2147483647 {
+ t.Errorf("-2147483648 %s 1 = %d, want -2147483647", "+", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != -1 {
+ t.Errorf("-2147483648 %s 2147483647 = %d, want -1", "+", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x + y
+ if r != 1 {
+ t.Errorf("-2147483647 %s -2147483648 = %d, want 1", "+", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != 2 {
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 2", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("-2147483647 %s -1 = %d, want -2147483648", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -2147483646 {
+ t.Errorf("-2147483647 %s 1 = %d, want -2147483646", "+", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 2147483647 = %d, want 0", "+", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x + y
+ if r != 2147483647 {
+ t.Errorf("-1 %s -2147483648 = %d, want 2147483647", "+", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("-1 %s -2147483647 = %d, want -2147483648", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2 {
+ t.Errorf("-1 %s -1 = %d, want -2", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("-1 %s 1 = %d, want 0", "+", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != 2147483646 {
+ t.Errorf("-1 %s 2147483647 = %d, want 2147483646", "+", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("0 %s -2147483648 = %d, want -2147483648", "+", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != -2147483647 {
+ t.Errorf("0 %s -2147483647 = %d, want -2147483647", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -1 {
+ t.Errorf("0 %s -1 = %d, want -1", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != 2147483647 {
+ t.Errorf("0 %s 2147483647 = %d, want 2147483647", "+", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x + y
+ if r != -2147483647 {
+ t.Errorf("1 %s -2147483648 = %d, want -2147483647", "+", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != -2147483646 {
+ t.Errorf("1 %s -2147483647 = %d, want -2147483646", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 %s -1 = %d, want 0", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("1 %s 2147483647 = %d, want -2147483648", "+", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x + y
+ if r != -1 {
+ t.Errorf("2147483647 %s -2147483648 = %d, want -1", "+", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != 0 {
+ t.Errorf("2147483647 %s -2147483647 = %d, want 0", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 2147483646 {
+ t.Errorf("2147483647 %s -1 = %d, want 2147483646", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("2147483647 %s 1 = %d, want -2147483648", "+", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != -2 {
+ t.Errorf("2147483647 %s 2147483647 = %d, want -2", "+", r)
+ }
+}
+func TestConstFoldint32sub(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x - y
+ if r != 0 {
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 0", "-", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != -1 {
+ t.Errorf("-2147483648 %s -2147483647 = %d, want -1", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -2147483647 {
+ t.Errorf("-2147483648 %s -1 = %d, want -2147483647", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 2147483647 {
+ t.Errorf("-2147483648 %s 1 = %d, want 2147483647", "-", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != 1 {
+ t.Errorf("-2147483648 %s 2147483647 = %d, want 1", "-", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x - y
+ if r != 1 {
+ t.Errorf("-2147483647 %s -2147483648 = %d, want 1", "-", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != 0 {
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 0", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -2147483646 {
+ t.Errorf("-2147483647 %s -1 = %d, want -2147483646", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("-2147483647 %s 1 = %d, want -2147483648", "-", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != 2 {
+ t.Errorf("-2147483647 %s 2147483647 = %d, want 2", "-", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x - y
+ if r != 2147483647 {
+ t.Errorf("-1 %s -2147483648 = %d, want 2147483647", "-", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != 2147483646 {
+ t.Errorf("-1 %s -2147483647 = %d, want 2147483646", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 0 {
+ t.Errorf("-1 %s -1 = %d, want 0", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "-", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("-1 %s 2147483647 = %d, want -2147483648", "-", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("0 %s -2147483648 = %d, want -2147483648", "-", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != 2147483647 {
+ t.Errorf("0 %s -2147483647 = %d, want 2147483647", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 %s -1 = %d, want 1", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -1 {
+ t.Errorf("0 %s 1 = %d, want -1", "-", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != -2147483647 {
+ t.Errorf("0 %s 2147483647 = %d, want -2147483647", "-", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x - y
+ if r != -2147483647 {
+ t.Errorf("1 %s -2147483648 = %d, want -2147483647", "-", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("1 %s -2147483647 = %d, want -2147483648", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 %s -1 = %d, want 2", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != -2147483646 {
+ t.Errorf("1 %s 2147483647 = %d, want -2147483646", "-", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x - y
+ if r != -1 {
+ t.Errorf("2147483647 %s -2147483648 = %d, want -1", "-", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != -2 {
+ t.Errorf("2147483647 %s -2147483647 = %d, want -2", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("2147483647 %s -1 = %d, want -2147483648", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 2147483646 {
+ t.Errorf("2147483647 %s 1 = %d, want 2147483646", "-", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != 0 {
+ t.Errorf("2147483647 %s 2147483647 = %d, want 0", "-", r)
+ }
+}
+func TestConstFoldint32div(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x / y
+ if r != 1 {
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 1", "/", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 1 {
+ t.Errorf("-2147483648 %s -2147483647 = %d, want 1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s -1 = %d, want -2147483648", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 1 = %d, want -2147483648", "/", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != -1 {
+ t.Errorf("-2147483648 %s 2147483647 = %d, want -1", "/", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("-2147483647 %s -2147483648 = %d, want 0", "/", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 1 {
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("-2147483647 %s -1 = %d, want 2147483647", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 1 = %d, want -2147483647", "/", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != -1 {
+ t.Errorf("-2147483647 %s 2147483647 = %d, want -1", "/", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -2147483648 = %d, want 0", "/", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -2147483647 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 1 {
+ t.Errorf("-1 %s -1 = %d, want 1", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", "/", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s 2147483647 = %d, want 0", "/", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -2147483648 = %d, want 0", "/", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -2147483647 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 2147483647 = %d, want 0", "/", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -2147483648 = %d, want 0", "/", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -2147483647 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -1 {
+ t.Errorf("1 %s -1 = %d, want -1", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 2147483647 = %d, want 0", "/", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("2147483647 %s -2147483648 = %d, want 0", "/", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != -1 {
+ t.Errorf("2147483647 %s -2147483647 = %d, want -1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("2147483647 %s -1 = %d, want -2147483647", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 1 = %d, want 2147483647", "/", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != 1 {
+ t.Errorf("2147483647 %s 2147483647 = %d, want 1", "/", r)
+ }
+}
+func TestConstFoldint32mul(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x * y
+ if r != 0 {
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 0", "*", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s -2147483647 = %d, want -2147483648", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s -1 = %d, want -2147483648", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 1 = %d, want -2147483648", "*", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 2147483647 = %d, want -2147483648", "*", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483647 %s -2147483648 = %d, want -2147483648", "*", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != 1 {
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 1", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 2147483647 {
+ t.Errorf("-2147483647 %s -1 = %d, want 2147483647", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 1 = %d, want -2147483647", "*", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != -1 {
+ t.Errorf("-2147483647 %s 2147483647 = %d, want -1", "*", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-1 %s -2147483648 = %d, want -2147483648", "*", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != 2147483647 {
+ t.Errorf("-1 %s -2147483647 = %d, want 2147483647", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 1 {
+ t.Errorf("-1 %s -1 = %d, want 1", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", "*", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != -2147483647 {
+ t.Errorf("-1 %s 2147483647 = %d, want -2147483647", "*", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -2147483648 = %d, want 0", "*", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -2147483647 = %d, want 0", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 2147483647 = %d, want 0", "*", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("1 %s -2147483648 = %d, want -2147483648", "*", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != -2147483647 {
+ t.Errorf("1 %s -2147483647 = %d, want -2147483647", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -1 {
+ t.Errorf("1 %s -1 = %d, want -1", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != 2147483647 {
+ t.Errorf("1 %s 2147483647 = %d, want 2147483647", "*", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("2147483647 %s -2147483648 = %d, want -2147483648", "*", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != -1 {
+ t.Errorf("2147483647 %s -2147483647 = %d, want -1", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -2147483647 {
+ t.Errorf("2147483647 %s -1 = %d, want -2147483647", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("2147483647 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 1 = %d, want 2147483647", "*", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != 1 {
+ t.Errorf("2147483647 %s 2147483647 = %d, want 1", "*", r)
+ }
+}
+func TestConstFoldint32mod(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 0", "%", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != -1 {
+ t.Errorf("-2147483648 %s -2147483647 = %d, want -1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483648 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "%", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != -1 {
+ t.Errorf("-2147483648 %s 2147483647 = %d, want -1", "%", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x % y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s -2147483648 = %d, want -2147483647", "%", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483647 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 1 = %d, want 0", "%", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 2147483647 = %d, want 0", "%", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -2147483648 = %d, want -1", "%", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -2147483647 = %d, want -1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s 2147483647 = %d, want -1", "%", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -2147483648 = %d, want 0", "%", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -2147483647 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 2147483647 = %d, want 0", "%", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -2147483648 = %d, want 1", "%", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -2147483647 = %d, want 1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 2147483647 = %d, want 1", "%", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x % y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s -2147483648 = %d, want 2147483647", "%", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("2147483647 %s -2147483647 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("2147483647 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("2147483647 %s 1 = %d, want 0", "%", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("2147483647 %s 2147483647 = %d, want 0", "%", r)
+ }
+}
+func TestConstFolduint16add(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
+ }
+ y = 65535
+ r = x + y
+ if r != 65535 {
+ t.Errorf("0 %s 65535 = %d, want 65535", "+", r)
+ }
+ x = 1
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
+ }
+ y = 65535
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "+", r)
+ }
+ x = 65535
+ y = 0
+ r = x + y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("65535 %s 1 = %d, want 0", "+", r)
+ }
+ y = 65535
+ r = x + y
+ if r != 65534 {
+ t.Errorf("65535 %s 65535 = %d, want 65534", "+", r)
+ }
+}
+func TestConstFolduint16sub(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 65535 {
+ t.Errorf("0 %s 1 = %d, want 65535", "-", r)
+ }
+ y = 65535
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 %s 65535 = %d, want 1", "-", r)
+ }
+ x = 1
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
+ }
+ y = 65535
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 %s 65535 = %d, want 2", "-", r)
+ }
+ x = 65535
+ y = 0
+ r = x - y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 65534 {
+ t.Errorf("65535 %s 1 = %d, want 65534", "-", r)
+ }
+ y = 65535
+ r = x - y
+ if r != 0 {
+ t.Errorf("65535 %s 65535 = %d, want 0", "-", r)
+ }
+}
+func TestConstFolduint16div(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
+ }
+ y = 65535
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "/", r)
+ }
+ x = 1
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
+ }
+ y = 65535
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "/", r)
+ }
+ x = 65535
+ y = 1
+ r = x / y
+ if r != 65535 {
+ t.Errorf("65535 %s 1 = %d, want 65535", "/", r)
+ }
+ y = 65535
+ r = x / y
+ if r != 1 {
+ t.Errorf("65535 %s 65535 = %d, want 1", "/", r)
+ }
+}
+func TestConstFolduint16mul(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
+ }
+ y = 65535
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "*", r)
+ }
+ x = 1
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
+ }
+ y = 65535
+ r = x * y
+ if r != 65535 {
+ t.Errorf("1 %s 65535 = %d, want 65535", "*", r)
+ }
+ x = 65535
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("65535 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 65535 {
+ t.Errorf("65535 %s 1 = %d, want 65535", "*", r)
+ }
+ y = 65535
+ r = x * y
+ if r != 1 {
+ t.Errorf("65535 %s 65535 = %d, want 1", "*", r)
+ }
+}
+func TestConstFolduint16mod(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
+ }
+ y = 65535
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "%", r)
+ }
+ x = 1
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 65535
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 65535 = %d, want 1", "%", r)
+ }
+ x = 65535
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("65535 %s 1 = %d, want 0", "%", r)
+ }
+ y = 65535
+ r = x % y
+ if r != 0 {
+ t.Errorf("65535 %s 65535 = %d, want 0", "%", r)
+ }
+}
+func TestConstFoldint16add(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x + y
+ if r != 0 {
+ t.Errorf("-32768 %s -32768 = %d, want 0", "+", r)
+ }
+ y = -32767
+ r = x + y
+ if r != 1 {
+ t.Errorf("-32768 %s -32767 = %d, want 1", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 32767 {
+ t.Errorf("-32768 %s -1 = %d, want 32767", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -32767 {
+ t.Errorf("-32768 %s 1 = %d, want -32767", "+", r)
+ }
+ y = 32766
+ r = x + y
+ if r != -2 {
+ t.Errorf("-32768 %s 32766 = %d, want -2", "+", r)
+ }
+ y = 32767
+ r = x + y
+ if r != -1 {
+ t.Errorf("-32768 %s 32767 = %d, want -1", "+", r)
+ }
+ x = -32767
+ y = -32768
+ r = x + y
+ if r != 1 {
+ t.Errorf("-32767 %s -32768 = %d, want 1", "+", r)
+ }
+ y = -32767
+ r = x + y
+ if r != 2 {
+ t.Errorf("-32767 %s -32767 = %d, want 2", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -32768 {
+ t.Errorf("-32767 %s -1 = %d, want -32768", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -32766 {
+ t.Errorf("-32767 %s 1 = %d, want -32766", "+", r)
+ }
+ y = 32766
+ r = x + y
+ if r != -1 {
+ t.Errorf("-32767 %s 32766 = %d, want -1", "+", r)
+ }
+ y = 32767
+ r = x + y
+ if r != 0 {
+ t.Errorf("-32767 %s 32767 = %d, want 0", "+", r)
+ }
+ x = -1
+ y = -32768
+ r = x + y
+ if r != 32767 {
+ t.Errorf("-1 %s -32768 = %d, want 32767", "+", r)
+ }
+ y = -32767
+ r = x + y
+ if r != -32768 {
+ t.Errorf("-1 %s -32767 = %d, want -32768", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2 {
+ t.Errorf("-1 %s -1 = %d, want -2", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("-1 %s 1 = %d, want 0", "+", r)
+ }
+ y = 32766
+ r = x + y
+ if r != 32765 {
+ t.Errorf("-1 %s 32766 = %d, want 32765", "+", r)
+ }
+ y = 32767
+ r = x + y
+ if r != 32766 {
+ t.Errorf("-1 %s 32767 = %d, want 32766", "+", r)
+ }
+ x = 0
+ y = -32768
+ r = x + y
+ if r != -32768 {
+ t.Errorf("0 %s -32768 = %d, want -32768", "+", r)
+ }
+ y = -32767
+ r = x + y
+ if r != -32767 {
+ t.Errorf("0 %s -32767 = %d, want -32767", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -1 {
+ t.Errorf("0 %s -1 = %d, want -1", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
+ }
+ y = 32766
+ r = x + y
+ if r != 32766 {
+ t.Errorf("0 %s 32766 = %d, want 32766", "+", r)
+ }
+ y = 32767
+ r = x + y
+ if r != 32767 {
+ t.Errorf("0 %s 32767 = %d, want 32767", "+", r)
+ }
+ x = 1
+ y = -32768
+ r = x + y
+ if r != -32767 {
+ t.Errorf("1 %s -32768 = %d, want -32767", "+", r)
+ }
+ y = -32767
+ r = x + y
+ if r != -32766 {
+ t.Errorf("1 %s -32767 = %d, want -32766", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 %s -1 = %d, want 0", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
+ }
+ y = 32766
+ r = x + y
+ if r != 32767 {
+ t.Errorf("1 %s 32766 = %d, want 32767", "+", r)
+ }
+ y = 32767
+ r = x + y
+ if r != -32768 {
+ t.Errorf("1 %s 32767 = %d, want -32768", "+", r)
+ }
+ x = 32766
+ y = -32768
+ r = x + y
+ if r != -2 {
+ t.Errorf("32766 %s -32768 = %d, want -2", "+", r)
+ }
+ y = -32767
+ r = x + y
+ if r != -1 {
+ t.Errorf("32766 %s -32767 = %d, want -1", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 32765 {
+ t.Errorf("32766 %s -1 = %d, want 32765", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 32767 {
+ t.Errorf("32766 %s 1 = %d, want 32767", "+", r)
+ }
+ y = 32766
+ r = x + y
+ if r != -4 {
+ t.Errorf("32766 %s 32766 = %d, want -4", "+", r)
+ }
+ y = 32767
+ r = x + y
+ if r != -3 {
+ t.Errorf("32766 %s 32767 = %d, want -3", "+", r)
+ }
+ x = 32767
+ y = -32768
+ r = x + y
+ if r != -1 {
+ t.Errorf("32767 %s -32768 = %d, want -1", "+", r)
+ }
+ y = -32767
+ r = x + y
+ if r != 0 {
+ t.Errorf("32767 %s -32767 = %d, want 0", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 32766 {
+ t.Errorf("32767 %s -1 = %d, want 32766", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -32768 {
+ t.Errorf("32767 %s 1 = %d, want -32768", "+", r)
+ }
+ y = 32766
+ r = x + y
+ if r != -3 {
+ t.Errorf("32767 %s 32766 = %d, want -3", "+", r)
+ }
+ y = 32767
+ r = x + y
+ if r != -2 {
+ t.Errorf("32767 %s 32767 = %d, want -2", "+", r)
+ }
+}
+func TestConstFoldint16sub(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x - y
+ if r != 0 {
+ t.Errorf("-32768 %s -32768 = %d, want 0", "-", r)
+ }
+ y = -32767
+ r = x - y
+ if r != -1 {
+ t.Errorf("-32768 %s -32767 = %d, want -1", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -32767 {
+ t.Errorf("-32768 %s -1 = %d, want -32767", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 32767 {
+ t.Errorf("-32768 %s 1 = %d, want 32767", "-", r)
+ }
+ y = 32766
+ r = x - y
+ if r != 2 {
+ t.Errorf("-32768 %s 32766 = %d, want 2", "-", r)
+ }
+ y = 32767
+ r = x - y
+ if r != 1 {
+ t.Errorf("-32768 %s 32767 = %d, want 1", "-", r)
+ }
+ x = -32767
+ y = -32768
+ r = x - y
+ if r != 1 {
+ t.Errorf("-32767 %s -32768 = %d, want 1", "-", r)
+ }
+ y = -32767
+ r = x - y
+ if r != 0 {
+ t.Errorf("-32767 %s -32767 = %d, want 0", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -32766 {
+ t.Errorf("-32767 %s -1 = %d, want -32766", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -32768 {
+ t.Errorf("-32767 %s 1 = %d, want -32768", "-", r)
+ }
+ y = 32766
+ r = x - y
+ if r != 3 {
+ t.Errorf("-32767 %s 32766 = %d, want 3", "-", r)
+ }
+ y = 32767
+ r = x - y
+ if r != 2 {
+ t.Errorf("-32767 %s 32767 = %d, want 2", "-", r)
+ }
+ x = -1
+ y = -32768
+ r = x - y
+ if r != 32767 {
+ t.Errorf("-1 %s -32768 = %d, want 32767", "-", r)
+ }
+ y = -32767
+ r = x - y
+ if r != 32766 {
+ t.Errorf("-1 %s -32767 = %d, want 32766", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 0 {
+ t.Errorf("-1 %s -1 = %d, want 0", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "-", r)
+ }
+ y = 32766
+ r = x - y
+ if r != -32767 {
+ t.Errorf("-1 %s 32766 = %d, want -32767", "-", r)
+ }
+ y = 32767
+ r = x - y
+ if r != -32768 {
+ t.Errorf("-1 %s 32767 = %d, want -32768", "-", r)
+ }
+ x = 0
+ y = -32768
+ r = x - y
+ if r != -32768 {
+ t.Errorf("0 %s -32768 = %d, want -32768", "-", r)
+ }
+ y = -32767
+ r = x - y
+ if r != 32767 {
+ t.Errorf("0 %s -32767 = %d, want 32767", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 %s -1 = %d, want 1", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -1 {
+ t.Errorf("0 %s 1 = %d, want -1", "-", r)
+ }
+ y = 32766
+ r = x - y
+ if r != -32766 {
+ t.Errorf("0 %s 32766 = %d, want -32766", "-", r)
+ }
+ y = 32767
+ r = x - y
+ if r != -32767 {
+ t.Errorf("0 %s 32767 = %d, want -32767", "-", r)
+ }
+ x = 1
+ y = -32768
+ r = x - y
+ if r != -32767 {
+ t.Errorf("1 %s -32768 = %d, want -32767", "-", r)
+ }
+ y = -32767
+ r = x - y
+ if r != -32768 {
+ t.Errorf("1 %s -32767 = %d, want -32768", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 %s -1 = %d, want 2", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
+ }
+ y = 32766
+ r = x - y
+ if r != -32765 {
+ t.Errorf("1 %s 32766 = %d, want -32765", "-", r)
+ }
+ y = 32767
+ r = x - y
+ if r != -32766 {
+ t.Errorf("1 %s 32767 = %d, want -32766", "-", r)
+ }
+ x = 32766
+ y = -32768
+ r = x - y
+ if r != -2 {
+ t.Errorf("32766 %s -32768 = %d, want -2", "-", r)
+ }
+ y = -32767
+ r = x - y
+ if r != -3 {
+ t.Errorf("32766 %s -32767 = %d, want -3", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 32767 {
+ t.Errorf("32766 %s -1 = %d, want 32767", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 32765 {
+ t.Errorf("32766 %s 1 = %d, want 32765", "-", r)
+ }
+ y = 32766
+ r = x - y
+ if r != 0 {
+ t.Errorf("32766 %s 32766 = %d, want 0", "-", r)
+ }
+ y = 32767
+ r = x - y
+ if r != -1 {
+ t.Errorf("32766 %s 32767 = %d, want -1", "-", r)
+ }
+ x = 32767
+ y = -32768
+ r = x - y
+ if r != -1 {
+ t.Errorf("32767 %s -32768 = %d, want -1", "-", r)
+ }
+ y = -32767
+ r = x - y
+ if r != -2 {
+ t.Errorf("32767 %s -32767 = %d, want -2", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -32768 {
+ t.Errorf("32767 %s -1 = %d, want -32768", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 32766 {
+ t.Errorf("32767 %s 1 = %d, want 32766", "-", r)
+ }
+ y = 32766
+ r = x - y
+ if r != 1 {
+ t.Errorf("32767 %s 32766 = %d, want 1", "-", r)
+ }
+ y = 32767
+ r = x - y
+ if r != 0 {
+ t.Errorf("32767 %s 32767 = %d, want 0", "-", r)
+ }
+}
+func TestConstFoldint16div(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x / y
+ if r != 1 {
+ t.Errorf("-32768 %s -32768 = %d, want 1", "/", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 1 {
+ t.Errorf("-32768 %s -32767 = %d, want 1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -32768 {
+ t.Errorf("-32768 %s -1 = %d, want -32768", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -32768 {
+ t.Errorf("-32768 %s 1 = %d, want -32768", "/", r)
+ }
+ y = 32766
+ r = x / y
+ if r != -1 {
+ t.Errorf("-32768 %s 32766 = %d, want -1", "/", r)
+ }
+ y = 32767
+ r = x / y
+ if r != -1 {
+ t.Errorf("-32768 %s 32767 = %d, want -1", "/", r)
+ }
+ x = -32767
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("-32767 %s -32768 = %d, want 0", "/", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 1 {
+ t.Errorf("-32767 %s -32767 = %d, want 1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 32767 {
+ t.Errorf("-32767 %s -1 = %d, want 32767", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -32767 {
+ t.Errorf("-32767 %s 1 = %d, want -32767", "/", r)
+ }
+ y = 32766
+ r = x / y
+ if r != -1 {
+ t.Errorf("-32767 %s 32766 = %d, want -1", "/", r)
+ }
+ y = 32767
+ r = x / y
+ if r != -1 {
+ t.Errorf("-32767 %s 32767 = %d, want -1", "/", r)
+ }
+ x = -1
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -32768 = %d, want 0", "/", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -32767 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 1 {
+ t.Errorf("-1 %s -1 = %d, want 1", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", "/", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s 32766 = %d, want 0", "/", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s 32767 = %d, want 0", "/", r)
+ }
+ x = 0
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -32768 = %d, want 0", "/", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -32767 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 32766 = %d, want 0", "/", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 32767 = %d, want 0", "/", r)
+ }
+ x = 1
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -32768 = %d, want 0", "/", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -32767 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -1 {
+ t.Errorf("1 %s -1 = %d, want -1", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 32766 = %d, want 0", "/", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 32767 = %d, want 0", "/", r)
+ }
+ x = 32766
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("32766 %s -32768 = %d, want 0", "/", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("32766 %s -32767 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -32766 {
+ t.Errorf("32766 %s -1 = %d, want -32766", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 32766 {
+ t.Errorf("32766 %s 1 = %d, want 32766", "/", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 1 {
+ t.Errorf("32766 %s 32766 = %d, want 1", "/", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("32766 %s 32767 = %d, want 0", "/", r)
+ }
+ x = 32767
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("32767 %s -32768 = %d, want 0", "/", r)
+ }
+ y = -32767
+ r = x / y
+ if r != -1 {
+ t.Errorf("32767 %s -32767 = %d, want -1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -32767 {
+ t.Errorf("32767 %s -1 = %d, want -32767", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 32767 {
+ t.Errorf("32767 %s 1 = %d, want 32767", "/", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 1 {
+ t.Errorf("32767 %s 32766 = %d, want 1", "/", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 1 {
+ t.Errorf("32767 %s 32767 = %d, want 1", "/", r)
+ }
+}
+func TestConstFoldint16mul(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x * y
+ if r != 0 {
+ t.Errorf("-32768 %s -32768 = %d, want 0", "*", r)
+ }
+ y = -32767
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32768 %s -32767 = %d, want -32768", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32768 %s -1 = %d, want -32768", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-32768 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32768 %s 1 = %d, want -32768", "*", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 0 {
+ t.Errorf("-32768 %s 32766 = %d, want 0", "*", r)
+ }
+ y = 32767
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32768 %s 32767 = %d, want -32768", "*", r)
+ }
+ x = -32767
+ y = -32768
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32767 %s -32768 = %d, want -32768", "*", r)
+ }
+ y = -32767
+ r = x * y
+ if r != 1 {
+ t.Errorf("-32767 %s -32767 = %d, want 1", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 32767 {
+ t.Errorf("-32767 %s -1 = %d, want 32767", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-32767 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -32767 {
+ t.Errorf("-32767 %s 1 = %d, want -32767", "*", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 32766 {
+ t.Errorf("-32767 %s 32766 = %d, want 32766", "*", r)
+ }
+ y = 32767
+ r = x * y
+ if r != -1 {
+ t.Errorf("-32767 %s 32767 = %d, want -1", "*", r)
+ }
+ x = -1
+ y = -32768
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-1 %s -32768 = %d, want -32768", "*", r)
+ }
+ y = -32767
+ r = x * y
+ if r != 32767 {
+ t.Errorf("-1 %s -32767 = %d, want 32767", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 1 {
+ t.Errorf("-1 %s -1 = %d, want 1", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", "*", r)
+ }
+ y = 32766
+ r = x * y
+ if r != -32766 {
+ t.Errorf("-1 %s 32766 = %d, want -32766", "*", r)
+ }
+ y = 32767
+ r = x * y
+ if r != -32767 {
+ t.Errorf("-1 %s 32767 = %d, want -32767", "*", r)
+ }
+ x = 0
+ y = -32768
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -32768 = %d, want 0", "*", r)
+ }
+ y = -32767
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -32767 = %d, want 0", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 32766 = %d, want 0", "*", r)
+ }
+ y = 32767
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 32767 = %d, want 0", "*", r)
+ }
+ x = 1
+ y = -32768
+ r = x * y
+ if r != -32768 {
+ t.Errorf("1 %s -32768 = %d, want -32768", "*", r)
+ }
+ y = -32767
+ r = x * y
+ if r != -32767 {
+ t.Errorf("1 %s -32767 = %d, want -32767", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -1 {
+ t.Errorf("1 %s -1 = %d, want -1", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 32766 {
+ t.Errorf("1 %s 32766 = %d, want 32766", "*", r)
+ }
+ y = 32767
+ r = x * y
+ if r != 32767 {
+ t.Errorf("1 %s 32767 = %d, want 32767", "*", r)
+ }
+ x = 32766
+ y = -32768
+ r = x * y
+ if r != 0 {
+ t.Errorf("32766 %s -32768 = %d, want 0", "*", r)
+ }
+ y = -32767
+ r = x * y
+ if r != 32766 {
+ t.Errorf("32766 %s -32767 = %d, want 32766", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -32766 {
+ t.Errorf("32766 %s -1 = %d, want -32766", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("32766 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 32766 {
+ t.Errorf("32766 %s 1 = %d, want 32766", "*", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 4 {
+ t.Errorf("32766 %s 32766 = %d, want 4", "*", r)
+ }
+ y = 32767
+ r = x * y
+ if r != -32766 {
+ t.Errorf("32766 %s 32767 = %d, want -32766", "*", r)
+ }
+ x = 32767
+ y = -32768
+ r = x * y
+ if r != -32768 {
+ t.Errorf("32767 %s -32768 = %d, want -32768", "*", r)
+ }
+ y = -32767
+ r = x * y
+ if r != -1 {
+ t.Errorf("32767 %s -32767 = %d, want -1", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -32767 {
+ t.Errorf("32767 %s -1 = %d, want -32767", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("32767 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 32767 {
+ t.Errorf("32767 %s 1 = %d, want 32767", "*", r)
+ }
+ y = 32766
+ r = x * y
+ if r != -32766 {
+ t.Errorf("32767 %s 32766 = %d, want -32766", "*", r)
+ }
+ y = 32767
+ r = x * y
+ if r != 1 {
+ t.Errorf("32767 %s 32767 = %d, want 1", "*", r)
+ }
+}
+func TestConstFoldint16mod(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32768 %s -32768 = %d, want 0", "%", r)
+ }
+ y = -32767
+ r = x % y
+ if r != -1 {
+ t.Errorf("-32768 %s -32767 = %d, want -1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32768 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32768 %s 1 = %d, want 0", "%", r)
+ }
+ y = 32766
+ r = x % y
+ if r != -2 {
+ t.Errorf("-32768 %s 32766 = %d, want -2", "%", r)
+ }
+ y = 32767
+ r = x % y
+ if r != -1 {
+ t.Errorf("-32768 %s 32767 = %d, want -1", "%", r)
+ }
+ x = -32767
+ y = -32768
+ r = x % y
+ if r != -32767 {
+ t.Errorf("-32767 %s -32768 = %d, want -32767", "%", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32767 %s -32767 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32767 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32767 %s 1 = %d, want 0", "%", r)
+ }
+ y = 32766
+ r = x % y
+ if r != -1 {
+ t.Errorf("-32767 %s 32766 = %d, want -1", "%", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32767 %s 32767 = %d, want 0", "%", r)
+ }
+ x = -1
+ y = -32768
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -32768 = %d, want -1", "%", r)
+ }
+ y = -32767
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -32767 = %d, want -1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 32766
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s 32766 = %d, want -1", "%", r)
+ }
+ y = 32767
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s 32767 = %d, want -1", "%", r)
+ }
+ x = 0
+ y = -32768
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -32768 = %d, want 0", "%", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -32767 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
+ }
+ y = 32766
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 32766 = %d, want 0", "%", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 32767 = %d, want 0", "%", r)
+ }
+ x = 1
+ y = -32768
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -32768 = %d, want 1", "%", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -32767 = %d, want 1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 32766
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 32766 = %d, want 1", "%", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 32767 = %d, want 1", "%", r)
+ }
+ x = 32766
+ y = -32768
+ r = x % y
+ if r != 32766 {
+ t.Errorf("32766 %s -32768 = %d, want 32766", "%", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 32766 {
+ t.Errorf("32766 %s -32767 = %d, want 32766", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("32766 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("32766 %s 1 = %d, want 0", "%", r)
+ }
+ y = 32766
+ r = x % y
+ if r != 0 {
+ t.Errorf("32766 %s 32766 = %d, want 0", "%", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 32766 {
+ t.Errorf("32766 %s 32767 = %d, want 32766", "%", r)
+ }
+ x = 32767
+ y = -32768
+ r = x % y
+ if r != 32767 {
+ t.Errorf("32767 %s -32768 = %d, want 32767", "%", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("32767 %s -32767 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("32767 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("32767 %s 1 = %d, want 0", "%", r)
+ }
+ y = 32766
+ r = x % y
+ if r != 1 {
+ t.Errorf("32767 %s 32766 = %d, want 1", "%", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("32767 %s 32767 = %d, want 0", "%", r)
+ }
+}
+func TestConstFolduint8add(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
+ }
+ y = 255
+ r = x + y
+ if r != 255 {
+ t.Errorf("0 %s 255 = %d, want 255", "+", r)
+ }
+ x = 1
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
+ }
+ y = 255
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "+", r)
+ }
+ x = 255
+ y = 0
+ r = x + y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("255 %s 1 = %d, want 0", "+", r)
+ }
+ y = 255
+ r = x + y
+ if r != 254 {
+ t.Errorf("255 %s 255 = %d, want 254", "+", r)
+ }
+}
+func TestConstFolduint8sub(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 255 {
+ t.Errorf("0 %s 1 = %d, want 255", "-", r)
+ }
+ y = 255
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 %s 255 = %d, want 1", "-", r)
+ }
+ x = 1
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
+ }
+ y = 255
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 %s 255 = %d, want 2", "-", r)
+ }
+ x = 255
+ y = 0
+ r = x - y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 254 {
+ t.Errorf("255 %s 1 = %d, want 254", "-", r)
+ }
+ y = 255
+ r = x - y
+ if r != 0 {
+ t.Errorf("255 %s 255 = %d, want 0", "-", r)
+ }
+}
+func TestConstFolduint8div(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
+ }
+ y = 255
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "/", r)
+ }
+ x = 1
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
+ }
+ y = 255
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "/", r)
+ }
+ x = 255
+ y = 1
+ r = x / y
+ if r != 255 {
+ t.Errorf("255 %s 1 = %d, want 255", "/", r)
+ }
+ y = 255
+ r = x / y
+ if r != 1 {
+ t.Errorf("255 %s 255 = %d, want 1", "/", r)
+ }
+}
+func TestConstFolduint8mul(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
+ }
+ y = 255
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "*", r)
+ }
+ x = 1
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
+ }
+ y = 255
+ r = x * y
+ if r != 255 {
+ t.Errorf("1 %s 255 = %d, want 255", "*", r)
+ }
+ x = 255
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("255 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 255 {
+ t.Errorf("255 %s 1 = %d, want 255", "*", r)
+ }
+ y = 255
+ r = x * y
+ if r != 1 {
+ t.Errorf("255 %s 255 = %d, want 1", "*", r)
+ }
+}
+func TestConstFolduint8mod(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
+ }
+ y = 255
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "%", r)
+ }
+ x = 1
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 255
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 255 = %d, want 1", "%", r)
+ }
+ x = 255
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("255 %s 1 = %d, want 0", "%", r)
+ }
+ y = 255
+ r = x % y
+ if r != 0 {
+ t.Errorf("255 %s 255 = %d, want 0", "%", r)
+ }
+}
+func TestConstFoldint8add(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x + y
+ if r != 0 {
+ t.Errorf("-128 %s -128 = %d, want 0", "+", r)
+ }
+ y = -127
+ r = x + y
+ if r != 1 {
+ t.Errorf("-128 %s -127 = %d, want 1", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 127 {
+ t.Errorf("-128 %s -1 = %d, want 127", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -127 {
+ t.Errorf("-128 %s 1 = %d, want -127", "+", r)
+ }
+ y = 126
+ r = x + y
+ if r != -2 {
+ t.Errorf("-128 %s 126 = %d, want -2", "+", r)
+ }
+ y = 127
+ r = x + y
+ if r != -1 {
+ t.Errorf("-128 %s 127 = %d, want -1", "+", r)
+ }
+ x = -127
+ y = -128
+ r = x + y
+ if r != 1 {
+ t.Errorf("-127 %s -128 = %d, want 1", "+", r)
+ }
+ y = -127
+ r = x + y
+ if r != 2 {
+ t.Errorf("-127 %s -127 = %d, want 2", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -128 {
+ t.Errorf("-127 %s -1 = %d, want -128", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -126 {
+ t.Errorf("-127 %s 1 = %d, want -126", "+", r)
+ }
+ y = 126
+ r = x + y
+ if r != -1 {
+ t.Errorf("-127 %s 126 = %d, want -1", "+", r)
+ }
+ y = 127
+ r = x + y
+ if r != 0 {
+ t.Errorf("-127 %s 127 = %d, want 0", "+", r)
+ }
+ x = -1
+ y = -128
+ r = x + y
+ if r != 127 {
+ t.Errorf("-1 %s -128 = %d, want 127", "+", r)
+ }
+ y = -127
+ r = x + y
+ if r != -128 {
+ t.Errorf("-1 %s -127 = %d, want -128", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2 {
+ t.Errorf("-1 %s -1 = %d, want -2", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("-1 %s 1 = %d, want 0", "+", r)
+ }
+ y = 126
+ r = x + y
+ if r != 125 {
+ t.Errorf("-1 %s 126 = %d, want 125", "+", r)
+ }
+ y = 127
+ r = x + y
+ if r != 126 {
+ t.Errorf("-1 %s 127 = %d, want 126", "+", r)
+ }
+ x = 0
+ y = -128
+ r = x + y
+ if r != -128 {
+ t.Errorf("0 %s -128 = %d, want -128", "+", r)
+ }
+ y = -127
+ r = x + y
+ if r != -127 {
+ t.Errorf("0 %s -127 = %d, want -127", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != -1 {
+ t.Errorf("0 %s -1 = %d, want -1", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
+ }
+ y = 126
+ r = x + y
+ if r != 126 {
+ t.Errorf("0 %s 126 = %d, want 126", "+", r)
+ }
+ y = 127
+ r = x + y
+ if r != 127 {
+ t.Errorf("0 %s 127 = %d, want 127", "+", r)
+ }
+ x = 1
+ y = -128
+ r = x + y
+ if r != -127 {
+ t.Errorf("1 %s -128 = %d, want -127", "+", r)
+ }
+ y = -127
+ r = x + y
+ if r != -126 {
+ t.Errorf("1 %s -127 = %d, want -126", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 %s -1 = %d, want 0", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
+ }
+ y = 126
+ r = x + y
+ if r != 127 {
+ t.Errorf("1 %s 126 = %d, want 127", "+", r)
+ }
+ y = 127
+ r = x + y
+ if r != -128 {
+ t.Errorf("1 %s 127 = %d, want -128", "+", r)
+ }
+ x = 126
+ y = -128
+ r = x + y
+ if r != -2 {
+ t.Errorf("126 %s -128 = %d, want -2", "+", r)
+ }
+ y = -127
+ r = x + y
+ if r != -1 {
+ t.Errorf("126 %s -127 = %d, want -1", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 125 {
+ t.Errorf("126 %s -1 = %d, want 125", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != 127 {
+ t.Errorf("126 %s 1 = %d, want 127", "+", r)
+ }
+ y = 126
+ r = x + y
+ if r != -4 {
+ t.Errorf("126 %s 126 = %d, want -4", "+", r)
+ }
+ y = 127
+ r = x + y
+ if r != -3 {
+ t.Errorf("126 %s 127 = %d, want -3", "+", r)
+ }
+ x = 127
+ y = -128
+ r = x + y
+ if r != -1 {
+ t.Errorf("127 %s -128 = %d, want -1", "+", r)
+ }
+ y = -127
+ r = x + y
+ if r != 0 {
+ t.Errorf("127 %s -127 = %d, want 0", "+", r)
+ }
+ y = -1
+ r = x + y
+ if r != 126 {
+ t.Errorf("127 %s -1 = %d, want 126", "+", r)
+ }
+ y = 0
+ r = x + y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", "+", r)
+ }
+ y = 1
+ r = x + y
+ if r != -128 {
+ t.Errorf("127 %s 1 = %d, want -128", "+", r)
+ }
+ y = 126
+ r = x + y
+ if r != -3 {
+ t.Errorf("127 %s 126 = %d, want -3", "+", r)
+ }
+ y = 127
+ r = x + y
+ if r != -2 {
+ t.Errorf("127 %s 127 = %d, want -2", "+", r)
+ }
+}
+func TestConstFoldint8sub(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x - y
+ if r != 0 {
+ t.Errorf("-128 %s -128 = %d, want 0", "-", r)
+ }
+ y = -127
+ r = x - y
+ if r != -1 {
+ t.Errorf("-128 %s -127 = %d, want -1", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -127 {
+ t.Errorf("-128 %s -1 = %d, want -127", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 127 {
+ t.Errorf("-128 %s 1 = %d, want 127", "-", r)
+ }
+ y = 126
+ r = x - y
+ if r != 2 {
+ t.Errorf("-128 %s 126 = %d, want 2", "-", r)
+ }
+ y = 127
+ r = x - y
+ if r != 1 {
+ t.Errorf("-128 %s 127 = %d, want 1", "-", r)
+ }
+ x = -127
+ y = -128
+ r = x - y
+ if r != 1 {
+ t.Errorf("-127 %s -128 = %d, want 1", "-", r)
+ }
+ y = -127
+ r = x - y
+ if r != 0 {
+ t.Errorf("-127 %s -127 = %d, want 0", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -126 {
+ t.Errorf("-127 %s -1 = %d, want -126", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -128 {
+ t.Errorf("-127 %s 1 = %d, want -128", "-", r)
+ }
+ y = 126
+ r = x - y
+ if r != 3 {
+ t.Errorf("-127 %s 126 = %d, want 3", "-", r)
+ }
+ y = 127
+ r = x - y
+ if r != 2 {
+ t.Errorf("-127 %s 127 = %d, want 2", "-", r)
+ }
+ x = -1
+ y = -128
+ r = x - y
+ if r != 127 {
+ t.Errorf("-1 %s -128 = %d, want 127", "-", r)
+ }
+ y = -127
+ r = x - y
+ if r != 126 {
+ t.Errorf("-1 %s -127 = %d, want 126", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 0 {
+ t.Errorf("-1 %s -1 = %d, want 0", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "-", r)
+ }
+ y = 126
+ r = x - y
+ if r != -127 {
+ t.Errorf("-1 %s 126 = %d, want -127", "-", r)
+ }
+ y = 127
+ r = x - y
+ if r != -128 {
+ t.Errorf("-1 %s 127 = %d, want -128", "-", r)
+ }
+ x = 0
+ y = -128
+ r = x - y
+ if r != -128 {
+ t.Errorf("0 %s -128 = %d, want -128", "-", r)
+ }
+ y = -127
+ r = x - y
+ if r != 127 {
+ t.Errorf("0 %s -127 = %d, want 127", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 %s -1 = %d, want 1", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != -1 {
+ t.Errorf("0 %s 1 = %d, want -1", "-", r)
+ }
+ y = 126
+ r = x - y
+ if r != -126 {
+ t.Errorf("0 %s 126 = %d, want -126", "-", r)
+ }
+ y = 127
+ r = x - y
+ if r != -127 {
+ t.Errorf("0 %s 127 = %d, want -127", "-", r)
+ }
+ x = 1
+ y = -128
+ r = x - y
+ if r != -127 {
+ t.Errorf("1 %s -128 = %d, want -127", "-", r)
+ }
+ y = -127
+ r = x - y
+ if r != -128 {
+ t.Errorf("1 %s -127 = %d, want -128", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 %s -1 = %d, want 2", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
+ }
+ y = 126
+ r = x - y
+ if r != -125 {
+ t.Errorf("1 %s 126 = %d, want -125", "-", r)
+ }
+ y = 127
+ r = x - y
+ if r != -126 {
+ t.Errorf("1 %s 127 = %d, want -126", "-", r)
+ }
+ x = 126
+ y = -128
+ r = x - y
+ if r != -2 {
+ t.Errorf("126 %s -128 = %d, want -2", "-", r)
+ }
+ y = -127
+ r = x - y
+ if r != -3 {
+ t.Errorf("126 %s -127 = %d, want -3", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != 127 {
+ t.Errorf("126 %s -1 = %d, want 127", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 125 {
+ t.Errorf("126 %s 1 = %d, want 125", "-", r)
+ }
+ y = 126
+ r = x - y
+ if r != 0 {
+ t.Errorf("126 %s 126 = %d, want 0", "-", r)
+ }
+ y = 127
+ r = x - y
+ if r != -1 {
+ t.Errorf("126 %s 127 = %d, want -1", "-", r)
+ }
+ x = 127
+ y = -128
+ r = x - y
+ if r != -1 {
+ t.Errorf("127 %s -128 = %d, want -1", "-", r)
+ }
+ y = -127
+ r = x - y
+ if r != -2 {
+ t.Errorf("127 %s -127 = %d, want -2", "-", r)
+ }
+ y = -1
+ r = x - y
+ if r != -128 {
+ t.Errorf("127 %s -1 = %d, want -128", "-", r)
+ }
+ y = 0
+ r = x - y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", "-", r)
+ }
+ y = 1
+ r = x - y
+ if r != 126 {
+ t.Errorf("127 %s 1 = %d, want 126", "-", r)
+ }
+ y = 126
+ r = x - y
+ if r != 1 {
+ t.Errorf("127 %s 126 = %d, want 1", "-", r)
+ }
+ y = 127
+ r = x - y
+ if r != 0 {
+ t.Errorf("127 %s 127 = %d, want 0", "-", r)
+ }
+}
+func TestConstFoldint8div(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x / y
+ if r != 1 {
+ t.Errorf("-128 %s -128 = %d, want 1", "/", r)
+ }
+ y = -127
+ r = x / y
+ if r != 1 {
+ t.Errorf("-128 %s -127 = %d, want 1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -128 {
+ t.Errorf("-128 %s -1 = %d, want -128", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -128 {
+ t.Errorf("-128 %s 1 = %d, want -128", "/", r)
+ }
+ y = 126
+ r = x / y
+ if r != -1 {
+ t.Errorf("-128 %s 126 = %d, want -1", "/", r)
+ }
+ y = 127
+ r = x / y
+ if r != -1 {
+ t.Errorf("-128 %s 127 = %d, want -1", "/", r)
+ }
+ x = -127
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("-127 %s -128 = %d, want 0", "/", r)
+ }
+ y = -127
+ r = x / y
+ if r != 1 {
+ t.Errorf("-127 %s -127 = %d, want 1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 127 {
+ t.Errorf("-127 %s -1 = %d, want 127", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -127 {
+ t.Errorf("-127 %s 1 = %d, want -127", "/", r)
+ }
+ y = 126
+ r = x / y
+ if r != -1 {
+ t.Errorf("-127 %s 126 = %d, want -1", "/", r)
+ }
+ y = 127
+ r = x / y
+ if r != -1 {
+ t.Errorf("-127 %s 127 = %d, want -1", "/", r)
+ }
+ x = -1
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -128 = %d, want 0", "/", r)
+ }
+ y = -127
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s -127 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 1 {
+ t.Errorf("-1 %s -1 = %d, want 1", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", "/", r)
+ }
+ y = 126
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s 126 = %d, want 0", "/", r)
+ }
+ y = 127
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 %s 127 = %d, want 0", "/", r)
+ }
+ x = 0
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -128 = %d, want 0", "/", r)
+ }
+ y = -127
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -127 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
+ }
+ y = 126
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 126 = %d, want 0", "/", r)
+ }
+ y = 127
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 %s 127 = %d, want 0", "/", r)
+ }
+ x = 1
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -128 = %d, want 0", "/", r)
+ }
+ y = -127
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s -127 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -1 {
+ t.Errorf("1 %s -1 = %d, want -1", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
+ }
+ y = 126
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 126 = %d, want 0", "/", r)
+ }
+ y = 127
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 %s 127 = %d, want 0", "/", r)
+ }
+ x = 126
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("126 %s -128 = %d, want 0", "/", r)
+ }
+ y = -127
+ r = x / y
+ if r != 0 {
+ t.Errorf("126 %s -127 = %d, want 0", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -126 {
+ t.Errorf("126 %s -1 = %d, want -126", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 126 {
+ t.Errorf("126 %s 1 = %d, want 126", "/", r)
+ }
+ y = 126
+ r = x / y
+ if r != 1 {
+ t.Errorf("126 %s 126 = %d, want 1", "/", r)
+ }
+ y = 127
+ r = x / y
+ if r != 0 {
+ t.Errorf("126 %s 127 = %d, want 0", "/", r)
+ }
+ x = 127
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("127 %s -128 = %d, want 0", "/", r)
+ }
+ y = -127
+ r = x / y
+ if r != -1 {
+ t.Errorf("127 %s -127 = %d, want -1", "/", r)
+ }
+ y = -1
+ r = x / y
+ if r != -127 {
+ t.Errorf("127 %s -1 = %d, want -127", "/", r)
+ }
+ y = 1
+ r = x / y
+ if r != 127 {
+ t.Errorf("127 %s 1 = %d, want 127", "/", r)
+ }
+ y = 126
+ r = x / y
+ if r != 1 {
+ t.Errorf("127 %s 126 = %d, want 1", "/", r)
+ }
+ y = 127
+ r = x / y
+ if r != 1 {
+ t.Errorf("127 %s 127 = %d, want 1", "/", r)
+ }
+}
+func TestConstFoldint8mul(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x * y
+ if r != 0 {
+ t.Errorf("-128 %s -128 = %d, want 0", "*", r)
+ }
+ y = -127
+ r = x * y
+ if r != -128 {
+ t.Errorf("-128 %s -127 = %d, want -128", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -128 {
+ t.Errorf("-128 %s -1 = %d, want -128", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-128 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -128 {
+ t.Errorf("-128 %s 1 = %d, want -128", "*", r)
+ }
+ y = 126
+ r = x * y
+ if r != 0 {
+ t.Errorf("-128 %s 126 = %d, want 0", "*", r)
+ }
+ y = 127
+ r = x * y
+ if r != -128 {
+ t.Errorf("-128 %s 127 = %d, want -128", "*", r)
+ }
+ x = -127
+ y = -128
+ r = x * y
+ if r != -128 {
+ t.Errorf("-127 %s -128 = %d, want -128", "*", r)
+ }
+ y = -127
+ r = x * y
+ if r != 1 {
+ t.Errorf("-127 %s -127 = %d, want 1", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 127 {
+ t.Errorf("-127 %s -1 = %d, want 127", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-127 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -127 {
+ t.Errorf("-127 %s 1 = %d, want -127", "*", r)
+ }
+ y = 126
+ r = x * y
+ if r != 126 {
+ t.Errorf("-127 %s 126 = %d, want 126", "*", r)
+ }
+ y = 127
+ r = x * y
+ if r != -1 {
+ t.Errorf("-127 %s 127 = %d, want -1", "*", r)
+ }
+ x = -1
+ y = -128
+ r = x * y
+ if r != -128 {
+ t.Errorf("-1 %s -128 = %d, want -128", "*", r)
+ }
+ y = -127
+ r = x * y
+ if r != 127 {
+ t.Errorf("-1 %s -127 = %d, want 127", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 1 {
+ t.Errorf("-1 %s -1 = %d, want 1", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", "*", r)
+ }
+ y = 126
+ r = x * y
+ if r != -126 {
+ t.Errorf("-1 %s 126 = %d, want -126", "*", r)
+ }
+ y = 127
+ r = x * y
+ if r != -127 {
+ t.Errorf("-1 %s 127 = %d, want -127", "*", r)
+ }
+ x = 0
+ y = -128
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -128 = %d, want 0", "*", r)
+ }
+ y = -127
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -127 = %d, want 0", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
+ }
+ y = 126
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 126 = %d, want 0", "*", r)
+ }
+ y = 127
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 %s 127 = %d, want 0", "*", r)
+ }
+ x = 1
+ y = -128
+ r = x * y
+ if r != -128 {
+ t.Errorf("1 %s -128 = %d, want -128", "*", r)
+ }
+ y = -127
+ r = x * y
+ if r != -127 {
+ t.Errorf("1 %s -127 = %d, want -127", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -1 {
+ t.Errorf("1 %s -1 = %d, want -1", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
+ }
+ y = 126
+ r = x * y
+ if r != 126 {
+ t.Errorf("1 %s 126 = %d, want 126", "*", r)
+ }
+ y = 127
+ r = x * y
+ if r != 127 {
+ t.Errorf("1 %s 127 = %d, want 127", "*", r)
+ }
+ x = 126
+ y = -128
+ r = x * y
+ if r != 0 {
+ t.Errorf("126 %s -128 = %d, want 0", "*", r)
+ }
+ y = -127
+ r = x * y
+ if r != 126 {
+ t.Errorf("126 %s -127 = %d, want 126", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -126 {
+ t.Errorf("126 %s -1 = %d, want -126", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("126 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 126 {
+ t.Errorf("126 %s 1 = %d, want 126", "*", r)
+ }
+ y = 126
+ r = x * y
+ if r != 4 {
+ t.Errorf("126 %s 126 = %d, want 4", "*", r)
+ }
+ y = 127
+ r = x * y
+ if r != -126 {
+ t.Errorf("126 %s 127 = %d, want -126", "*", r)
+ }
+ x = 127
+ y = -128
+ r = x * y
+ if r != -128 {
+ t.Errorf("127 %s -128 = %d, want -128", "*", r)
+ }
+ y = -127
+ r = x * y
+ if r != -1 {
+ t.Errorf("127 %s -127 = %d, want -1", "*", r)
+ }
+ y = -1
+ r = x * y
+ if r != -127 {
+ t.Errorf("127 %s -1 = %d, want -127", "*", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("127 %s 0 = %d, want 0", "*", r)
+ }
+ y = 1
+ r = x * y
+ if r != 127 {
+ t.Errorf("127 %s 1 = %d, want 127", "*", r)
+ }
+ y = 126
+ r = x * y
+ if r != -126 {
+ t.Errorf("127 %s 126 = %d, want -126", "*", r)
+ }
+ y = 127
+ r = x * y
+ if r != 1 {
+ t.Errorf("127 %s 127 = %d, want 1", "*", r)
+ }
+}
+func TestConstFoldint8mod(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x % y
+ if r != 0 {
+ t.Errorf("-128 %s -128 = %d, want 0", "%", r)
+ }
+ y = -127
+ r = x % y
+ if r != -1 {
+ t.Errorf("-128 %s -127 = %d, want -1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-128 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-128 %s 1 = %d, want 0", "%", r)
+ }
+ y = 126
+ r = x % y
+ if r != -2 {
+ t.Errorf("-128 %s 126 = %d, want -2", "%", r)
+ }
+ y = 127
+ r = x % y
+ if r != -1 {
+ t.Errorf("-128 %s 127 = %d, want -1", "%", r)
+ }
+ x = -127
+ y = -128
+ r = x % y
+ if r != -127 {
+ t.Errorf("-127 %s -128 = %d, want -127", "%", r)
+ }
+ y = -127
+ r = x % y
+ if r != 0 {
+ t.Errorf("-127 %s -127 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-127 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-127 %s 1 = %d, want 0", "%", r)
+ }
+ y = 126
+ r = x % y
+ if r != -1 {
+ t.Errorf("-127 %s 126 = %d, want -1", "%", r)
+ }
+ y = 127
+ r = x % y
+ if r != 0 {
+ t.Errorf("-127 %s 127 = %d, want 0", "%", r)
+ }
+ x = -1
+ y = -128
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -128 = %d, want -1", "%", r)
+ }
+ y = -127
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s -127 = %d, want -1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 126
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s 126 = %d, want -1", "%", r)
+ }
+ y = 127
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 %s 127 = %d, want -1", "%", r)
+ }
+ x = 0
+ y = -128
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -128 = %d, want 0", "%", r)
+ }
+ y = -127
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -127 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
+ }
+ y = 126
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 126 = %d, want 0", "%", r)
+ }
+ y = 127
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 %s 127 = %d, want 0", "%", r)
+ }
+ x = 1
+ y = -128
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -128 = %d, want 1", "%", r)
+ }
+ y = -127
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s -127 = %d, want 1", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
+ }
+ y = 126
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 126 = %d, want 1", "%", r)
+ }
+ y = 127
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 %s 127 = %d, want 1", "%", r)
+ }
+ x = 126
+ y = -128
+ r = x % y
+ if r != 126 {
+ t.Errorf("126 %s -128 = %d, want 126", "%", r)
+ }
+ y = -127
+ r = x % y
+ if r != 126 {
+ t.Errorf("126 %s -127 = %d, want 126", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("126 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("126 %s 1 = %d, want 0", "%", r)
+ }
+ y = 126
+ r = x % y
+ if r != 0 {
+ t.Errorf("126 %s 126 = %d, want 0", "%", r)
+ }
+ y = 127
+ r = x % y
+ if r != 126 {
+ t.Errorf("126 %s 127 = %d, want 126", "%", r)
+ }
+ x = 127
+ y = -128
+ r = x % y
+ if r != 127 {
+ t.Errorf("127 %s -128 = %d, want 127", "%", r)
+ }
+ y = -127
+ r = x % y
+ if r != 0 {
+ t.Errorf("127 %s -127 = %d, want 0", "%", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("127 %s -1 = %d, want 0", "%", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("127 %s 1 = %d, want 0", "%", r)
+ }
+ y = 126
+ r = x % y
+ if r != 1 {
+ t.Errorf("127 %s 126 = %d, want 1", "%", r)
+ }
+ y = 127
+ r = x % y
+ if r != 0 {
+ t.Errorf("127 %s 127 = %d, want 0", "%", r)
+ }
+}
+func TestConstFolduint64uint64lsh(t *testing.T) {
+ var x, r uint64
+ var y uint64
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x << y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint64uint64rsh(t *testing.T) {
+ var x, r uint64
+ var y uint64
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x >> y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 9223372036854775807", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint64uint32lsh(t *testing.T) {
+ var x, r uint64
+ var y uint32
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x << y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 4294967295 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint64uint32rsh(t *testing.T) {
+ var x, r uint64
+ var y uint32
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x >> y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 9223372036854775807", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 4294967295 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint64uint16lsh(t *testing.T) {
+ var x, r uint64
+ var y uint16
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x << y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 65535 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint64uint16rsh(t *testing.T) {
+ var x, r uint64
+ var y uint16
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x >> y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 9223372036854775807", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 65535 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint64uint8lsh(t *testing.T) {
+ var x, r uint64
+ var y uint8
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x << y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 255 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint64uint8rsh(t *testing.T) {
+ var x, r uint64
+ var y uint8
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x >> y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("18446744073709551615 %s 1 = %d, want 9223372036854775807", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 %s 255 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint64uint64lsh(t *testing.T) {
+ var x, r int64
+ var y uint64
+ x = -9223372036854775808
+ y = 0
+ r = x << y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x << y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x << y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 %s 1 = %d, want -8589934592", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x << y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x << y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint64uint64rsh(t *testing.T) {
+ var x, r int64
+ var y uint64
+ x = -9223372036854775808
+ y = 0
+ r = x >> y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -4611686018427387904", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x >> y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -4611686018427387904", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x >> y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-4294967296 %s 1 = %d, want -2147483648", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x >> y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 4611686018427387903", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want 4611686018427387903", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint64uint32lsh(t *testing.T) {
+ var x, r int64
+ var y uint32
+ x = -9223372036854775808
+ y = 0
+ r = x << y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x << y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x << y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 %s 1 = %d, want -8589934592", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x << y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x << y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 4294967295 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint64uint32rsh(t *testing.T) {
+ var x, r int64
+ var y uint32
+ x = -9223372036854775808
+ y = 0
+ r = x >> y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -4611686018427387904", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x >> y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -4611686018427387904", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x >> y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-4294967296 %s 1 = %d, want -2147483648", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x >> y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 4611686018427387903", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want 4611686018427387903", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 4294967295 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint64uint16lsh(t *testing.T) {
+ var x, r int64
+ var y uint16
+ x = -9223372036854775808
+ y = 0
+ r = x << y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x << y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x << y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 %s 1 = %d, want -8589934592", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x << y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x << y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 65535 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint64uint16rsh(t *testing.T) {
+ var x, r int64
+ var y uint16
+ x = -9223372036854775808
+ y = 0
+ r = x >> y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -4611686018427387904", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x >> y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -4611686018427387904", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x >> y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-4294967296 %s 1 = %d, want -2147483648", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x >> y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 4611686018427387903", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want 4611686018427387903", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 65535 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint64uint8lsh(t *testing.T) {
+ var x, r int64
+ var y uint8
+ x = -9223372036854775808
+ y = 0
+ r = x << y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x << y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x << y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 %s 1 = %d, want -8589934592", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x << y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x << y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 255 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint64uint8rsh(t *testing.T) {
+ var x, r int64
+ var y uint8
+ x = -9223372036854775808
+ y = 0
+ r = x >> y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -4611686018427387904", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x >> y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -4611686018427387904", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x >> y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-4294967296 %s 1 = %d, want -2147483648", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 255 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x >> y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775806 %s 1 = %d, want 4611686018427387903", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775807 %s 1 = %d, want 4611686018427387903", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 %s 255 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint32uint64lsh(t *testing.T) {
+ var x, r uint32
+ var y uint64
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x << y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 4294967294 {
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint32uint64rsh(t *testing.T) {
+ var x, r uint32
+ var y uint64
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x >> y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("4294967295 %s 1 = %d, want 2147483647", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint32uint32lsh(t *testing.T) {
+ var x, r uint32
+ var y uint32
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x << y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 4294967294 {
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 %s 4294967295 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint32uint32rsh(t *testing.T) {
+ var x, r uint32
+ var y uint32
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x >> y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("4294967295 %s 1 = %d, want 2147483647", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 %s 4294967295 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint32uint16lsh(t *testing.T) {
+ var x, r uint32
+ var y uint16
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x << y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 4294967294 {
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 %s 65535 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint32uint16rsh(t *testing.T) {
+ var x, r uint32
+ var y uint16
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x >> y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("4294967295 %s 1 = %d, want 2147483647", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 %s 65535 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint32uint8lsh(t *testing.T) {
+ var x, r uint32
+ var y uint8
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x << y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 4294967294 {
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 %s 255 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint32uint8rsh(t *testing.T) {
+ var x, r uint32
+ var y uint8
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x >> y
+ if r != 4294967295 {
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("4294967295 %s 1 = %d, want 2147483647", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 %s 255 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint32uint64lsh(t *testing.T) {
+ var x, r int32
+ var y uint64
+ x = -2147483648
+ y = 0
+ r = x << y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x << y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-2147483647 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x << y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("2147483647 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint32uint64rsh(t *testing.T) {
+ var x, r int32
+ var y uint64
+ x = -2147483648
+ y = 0
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483648 %s 1 = %d, want -1073741824", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x >> y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483647 %s 1 = %d, want -1073741824", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 1073741823 {
+ t.Errorf("2147483647 %s 1 = %d, want 1073741823", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint32uint32lsh(t *testing.T) {
+ var x, r int32
+ var y uint32
+ x = -2147483648
+ y = 0
+ r = x << y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x << y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-2147483647 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x << y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("2147483647 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 %s 4294967295 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint32uint32rsh(t *testing.T) {
+ var x, r int32
+ var y uint32
+ x = -2147483648
+ y = 0
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483648 %s 1 = %d, want -1073741824", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x >> y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483647 %s 1 = %d, want -1073741824", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 1073741823 {
+ t.Errorf("2147483647 %s 1 = %d, want 1073741823", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 %s 4294967295 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint32uint16lsh(t *testing.T) {
+ var x, r int32
+ var y uint16
+ x = -2147483648
+ y = 0
+ r = x << y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x << y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-2147483647 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x << y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("2147483647 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 %s 65535 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint32uint16rsh(t *testing.T) {
+ var x, r int32
+ var y uint16
+ x = -2147483648
+ y = 0
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483648 %s 1 = %d, want -1073741824", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x >> y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483647 %s 1 = %d, want -1073741824", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 1073741823 {
+ t.Errorf("2147483647 %s 1 = %d, want 1073741823", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 %s 65535 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint32uint8lsh(t *testing.T) {
+ var x, r int32
+ var y uint8
+ x = -2147483648
+ y = 0
+ r = x << y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x << y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-2147483647 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x << y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("2147483647 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 %s 255 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint32uint8rsh(t *testing.T) {
+ var x, r int32
+ var y uint8
+ x = -2147483648
+ y = 0
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483648 %s 1 = %d, want -1073741824", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x >> y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483647 %s 1 = %d, want -1073741824", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 255 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 1073741823 {
+ t.Errorf("2147483647 %s 1 = %d, want 1073741823", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 %s 255 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint16uint64lsh(t *testing.T) {
+ var x, r uint16
+ var y uint64
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 65535
+ y = 0
+ r = x << y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 65534 {
+ t.Errorf("65535 %s 1 = %d, want 65534", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint16uint64rsh(t *testing.T) {
+ var x, r uint16
+ var y uint64
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 65535
+ y = 0
+ r = x >> y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("65535 %s 1 = %d, want 32767", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint16uint32lsh(t *testing.T) {
+ var x, r uint16
+ var y uint32
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 65535
+ y = 0
+ r = x << y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 65534 {
+ t.Errorf("65535 %s 1 = %d, want 65534", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 %s 4294967295 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint16uint32rsh(t *testing.T) {
+ var x, r uint16
+ var y uint32
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 65535
+ y = 0
+ r = x >> y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("65535 %s 1 = %d, want 32767", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 %s 4294967295 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint16uint16lsh(t *testing.T) {
+ var x, r uint16
+ var y uint16
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 65535
+ y = 0
+ r = x << y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 65534 {
+ t.Errorf("65535 %s 1 = %d, want 65534", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 %s 65535 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint16uint16rsh(t *testing.T) {
+ var x, r uint16
+ var y uint16
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 65535
+ y = 0
+ r = x >> y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("65535 %s 1 = %d, want 32767", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 %s 65535 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint16uint8lsh(t *testing.T) {
+ var x, r uint16
+ var y uint8
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 65535
+ y = 0
+ r = x << y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 65534 {
+ t.Errorf("65535 %s 1 = %d, want 65534", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 %s 255 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint16uint8rsh(t *testing.T) {
+ var x, r uint16
+ var y uint8
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 65535
+ y = 0
+ r = x >> y
+ if r != 65535 {
+ t.Errorf("65535 %s 0 = %d, want 65535", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("65535 %s 1 = %d, want 32767", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 %s 255 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint16uint64lsh(t *testing.T) {
+ var x, r int16
+ var y uint64
+ x = -32768
+ y = 0
+ r = x << y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -32767
+ y = 0
+ r = x << y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-32767 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 32766
+ y = 0
+ r = x << y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("32766 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 32767
+ y = 0
+ r = x << y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("32767 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint16uint64rsh(t *testing.T) {
+ var x, r int16
+ var y uint64
+ x = -32768
+ y = 0
+ r = x >> y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32768 %s 1 = %d, want -16384", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -32767
+ y = 0
+ r = x >> y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32767 %s 1 = %d, want -16384", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 32766
+ y = 0
+ r = x >> y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32766 %s 1 = %d, want 16383", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 32767
+ y = 0
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32767 %s 1 = %d, want 16383", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint16uint32lsh(t *testing.T) {
+ var x, r int16
+ var y uint32
+ x = -32768
+ y = 0
+ r = x << y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -32767
+ y = 0
+ r = x << y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-32767 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 32766
+ y = 0
+ r = x << y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("32766 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 32767
+ y = 0
+ r = x << y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("32767 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 %s 4294967295 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint16uint32rsh(t *testing.T) {
+ var x, r int16
+ var y uint32
+ x = -32768
+ y = 0
+ r = x >> y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32768 %s 1 = %d, want -16384", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -32767
+ y = 0
+ r = x >> y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32767 %s 1 = %d, want -16384", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 32766
+ y = 0
+ r = x >> y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32766 %s 1 = %d, want 16383", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 32767
+ y = 0
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32767 %s 1 = %d, want 16383", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 %s 4294967295 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint16uint16lsh(t *testing.T) {
+ var x, r int16
+ var y uint16
+ x = -32768
+ y = 0
+ r = x << y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -32767
+ y = 0
+ r = x << y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-32767 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 32766
+ y = 0
+ r = x << y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("32766 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 32767
+ y = 0
+ r = x << y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("32767 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 %s 65535 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint16uint16rsh(t *testing.T) {
+ var x, r int16
+ var y uint16
+ x = -32768
+ y = 0
+ r = x >> y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32768 %s 1 = %d, want -16384", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -32767
+ y = 0
+ r = x >> y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32767 %s 1 = %d, want -16384", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 32766
+ y = 0
+ r = x >> y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32766 %s 1 = %d, want 16383", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 32767
+ y = 0
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32767 %s 1 = %d, want 16383", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 %s 65535 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint16uint8lsh(t *testing.T) {
+ var x, r int16
+ var y uint8
+ x = -32768
+ y = 0
+ r = x << y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -32767
+ y = 0
+ r = x << y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-32767 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 32766
+ y = 0
+ r = x << y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("32766 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 32767
+ y = 0
+ r = x << y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("32767 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 %s 255 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint16uint8rsh(t *testing.T) {
+ var x, r int16
+ var y uint8
+ x = -32768
+ y = 0
+ r = x >> y
+ if r != -32768 {
+ t.Errorf("-32768 %s 0 = %d, want -32768", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32768 %s 1 = %d, want -16384", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -32767
+ y = 0
+ r = x >> y
+ if r != -32767 {
+ t.Errorf("-32767 %s 0 = %d, want -32767", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32767 %s 1 = %d, want -16384", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 255 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 32766
+ y = 0
+ r = x >> y
+ if r != 32766 {
+ t.Errorf("32766 %s 0 = %d, want 32766", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32766 %s 1 = %d, want 16383", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 32767
+ y = 0
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("32767 %s 0 = %d, want 32767", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32767 %s 1 = %d, want 16383", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 %s 255 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint8uint64lsh(t *testing.T) {
+ var x, r uint8
+ var y uint64
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 255
+ y = 0
+ r = x << y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 254 {
+ t.Errorf("255 %s 1 = %d, want 254", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint8uint64rsh(t *testing.T) {
+ var x, r uint8
+ var y uint64
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 255
+ y = 0
+ r = x >> y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 127 {
+ t.Errorf("255 %s 1 = %d, want 127", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint8uint32lsh(t *testing.T) {
+ var x, r uint8
+ var y uint32
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 255
+ y = 0
+ r = x << y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 254 {
+ t.Errorf("255 %s 1 = %d, want 254", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 %s 4294967295 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint8uint32rsh(t *testing.T) {
+ var x, r uint8
+ var y uint32
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 255
+ y = 0
+ r = x >> y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 127 {
+ t.Errorf("255 %s 1 = %d, want 127", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 %s 4294967295 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint8uint16lsh(t *testing.T) {
+ var x, r uint8
+ var y uint16
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 255
+ y = 0
+ r = x << y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 254 {
+ t.Errorf("255 %s 1 = %d, want 254", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 %s 65535 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint8uint16rsh(t *testing.T) {
+ var x, r uint8
+ var y uint16
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 255
+ y = 0
+ r = x >> y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 127 {
+ t.Errorf("255 %s 1 = %d, want 127", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 %s 65535 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFolduint8uint8lsh(t *testing.T) {
+ var x, r uint8
+ var y uint8
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 255
+ y = 0
+ r = x << y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 254 {
+ t.Errorf("255 %s 1 = %d, want 254", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 %s 255 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFolduint8uint8rsh(t *testing.T) {
+ var x, r uint8
+ var y uint8
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 255
+ y = 0
+ r = x >> y
+ if r != 255 {
+ t.Errorf("255 %s 0 = %d, want 255", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 127 {
+ t.Errorf("255 %s 1 = %d, want 127", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 %s 255 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint8uint64lsh(t *testing.T) {
+ var x, r int8
+ var y uint64
+ x = -128
+ y = 0
+ r = x << y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -127
+ y = 0
+ r = x << y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-127 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 126
+ y = 0
+ r = x << y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("126 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+ x = 127
+ y = 0
+ r = x << y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("127 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 %s 4294967296 = %d, want 0", "<<", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 %s 18446744073709551615 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint8uint64rsh(t *testing.T) {
+ var x, r int8
+ var y uint64
+ x = -128
+ y = 0
+ r = x >> y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-128 %s 1 = %d, want -64", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -127
+ y = 0
+ r = x >> y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-127 %s 1 = %d, want -64", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967296 = %d, want -1", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 18446744073709551615 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 126
+ y = 0
+ r = x >> y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("126 %s 1 = %d, want 63", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+ x = 127
+ y = 0
+ r = x >> y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("127 %s 1 = %d, want 63", ">>", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 %s 4294967296 = %d, want 0", ">>", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 %s 18446744073709551615 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint8uint32lsh(t *testing.T) {
+ var x, r int8
+ var y uint32
+ x = -128
+ y = 0
+ r = x << y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -127
+ y = 0
+ r = x << y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-127 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 126
+ y = 0
+ r = x << y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("126 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 %s 4294967295 = %d, want 0", "<<", r)
+ }
+ x = 127
+ y = 0
+ r = x << y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("127 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 %s 4294967295 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint8uint32rsh(t *testing.T) {
+ var x, r int8
+ var y uint32
+ x = -128
+ y = 0
+ r = x >> y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-128 %s 1 = %d, want -64", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -127
+ y = 0
+ r = x >> y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-127 %s 1 = %d, want -64", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 4294967295 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 126
+ y = 0
+ r = x >> y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("126 %s 1 = %d, want 63", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 %s 4294967295 = %d, want 0", ">>", r)
+ }
+ x = 127
+ y = 0
+ r = x >> y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("127 %s 1 = %d, want 63", ">>", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 %s 4294967295 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint8uint16lsh(t *testing.T) {
+ var x, r int8
+ var y uint16
+ x = -128
+ y = 0
+ r = x << y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -127
+ y = 0
+ r = x << y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-127 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 126
+ y = 0
+ r = x << y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("126 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 %s 65535 = %d, want 0", "<<", r)
+ }
+ x = 127
+ y = 0
+ r = x << y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("127 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 %s 65535 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint8uint16rsh(t *testing.T) {
+ var x, r int8
+ var y uint16
+ x = -128
+ y = 0
+ r = x >> y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-128 %s 1 = %d, want -64", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -127
+ y = 0
+ r = x >> y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-127 %s 1 = %d, want -64", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 65535 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 126
+ y = 0
+ r = x >> y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("126 %s 1 = %d, want 63", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 %s 65535 = %d, want 0", ">>", r)
+ }
+ x = 127
+ y = 0
+ r = x >> y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("127 %s 1 = %d, want 63", ">>", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 %s 65535 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldint8uint8lsh(t *testing.T) {
+ var x, r int8
+ var y uint8
+ x = -128
+ y = 0
+ r = x << y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -127
+ y = 0
+ r = x << y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-127 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 %s 255 = %d, want 0", "<<", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 126
+ y = 0
+ r = x << y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("126 %s 1 = %d, want -4", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 %s 255 = %d, want 0", "<<", r)
+ }
+ x = 127
+ y = 0
+ r = x << y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", "<<", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("127 %s 1 = %d, want -2", "<<", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 %s 255 = %d, want 0", "<<", r)
+ }
+}
+func TestConstFoldint8uint8rsh(t *testing.T) {
+ var x, r int8
+ var y uint8
+ x = -128
+ y = 0
+ r = x >> y
+ if r != -128 {
+ t.Errorf("-128 %s 0 = %d, want -128", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-128 %s 1 = %d, want -64", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -127
+ y = 0
+ r = x >> y
+ if r != -127 {
+ t.Errorf("-127 %s 0 = %d, want -127", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-127 %s 1 = %d, want -64", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 %s 255 = %d, want -1", ">>", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 %s 255 = %d, want -1", ">>", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 126
+ y = 0
+ r = x >> y
+ if r != 126 {
+ t.Errorf("126 %s 0 = %d, want 126", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("126 %s 1 = %d, want 63", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 %s 255 = %d, want 0", ">>", r)
+ }
+ x = 127
+ y = 0
+ r = x >> y
+ if r != 127 {
+ t.Errorf("127 %s 0 = %d, want 127", ">>", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("127 %s 1 = %d, want 63", ">>", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 %s 255 = %d, want 0", ">>", r)
+ }
+}
+func TestConstFoldCompareuint64(t *testing.T) {
+ {
+ var x uint64 = 0
+ var y uint64 = 0
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 0
+ var y uint64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint64 = 0
+ var y uint64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint64 = 0
+ var y uint64 = 18446744073709551615
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint64 = 1
+ var y uint64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 1
+ var y uint64 = 1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 1
+ var y uint64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint64 = 1
+ var y uint64 = 18446744073709551615
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint64 = 4294967296
+ var y uint64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 4294967296
+ var y uint64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 4294967296
+ var y uint64 = 4294967296
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 4294967296
+ var y uint64 = 18446744073709551615
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint64 = 18446744073709551615
+ var y uint64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 18446744073709551615
+ var y uint64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 18446744073709551615
+ var y uint64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint64 = 18446744073709551615
+ var y uint64 = 18446744073709551615
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+}
+func TestConstFoldCompareint64(t *testing.T) {
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = -9223372036854775808
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = -9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = -4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = 9223372036854775806
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775808
+ var y int64 = 9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = -9223372036854775808
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = -9223372036854775807
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = -4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = 9223372036854775806
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -9223372036854775807
+ var y int64 = 9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = -9223372036854775808
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = -9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = -4294967296
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = 9223372036854775806
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -4294967296
+ var y int64 = 9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = -9223372036854775808
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = -9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = -4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = -1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = 9223372036854775806
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = -1
+ var y int64 = 9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = -9223372036854775808
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = -9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = -4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = 0
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = 9223372036854775806
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 0
+ var y int64 = 9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = -9223372036854775808
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = -9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = -4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = 1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = 9223372036854775806
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 1
+ var y int64 = 9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = -9223372036854775808
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = -9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = -4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = 4294967296
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = 9223372036854775806
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 4294967296
+ var y int64 = 9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = -9223372036854775808
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = -9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = -4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = 9223372036854775806
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775806
+ var y int64 = 9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = -9223372036854775808
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = -9223372036854775807
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = -4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = 4294967296
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = 9223372036854775806
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int64 = 9223372036854775807
+ var y int64 = 9223372036854775807
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+}
+func TestConstFoldCompareuint32(t *testing.T) {
+ {
+ var x uint32 = 0
+ var y uint32 = 0
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint32 = 0
+ var y uint32 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint32 = 0
+ var y uint32 = 4294967295
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint32 = 1
+ var y uint32 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint32 = 1
+ var y uint32 = 1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint32 = 1
+ var y uint32 = 4294967295
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint32 = 4294967295
+ var y uint32 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint32 = 4294967295
+ var y uint32 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint32 = 4294967295
+ var y uint32 = 4294967295
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+}
+func TestConstFoldCompareint32(t *testing.T) {
+ {
+ var x int32 = -2147483648
+ var y int32 = -2147483648
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483648
+ var y int32 = -2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483648
+ var y int32 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483648
+ var y int32 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483648
+ var y int32 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483648
+ var y int32 = 2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483647
+ var y int32 = -2147483648
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483647
+ var y int32 = -2147483647
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483647
+ var y int32 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483647
+ var y int32 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483647
+ var y int32 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -2147483647
+ var y int32 = 2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -1
+ var y int32 = -2147483648
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = -1
+ var y int32 = -2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = -1
+ var y int32 = -1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = -1
+ var y int32 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -1
+ var y int32 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = -1
+ var y int32 = 2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = 0
+ var y int32 = -2147483648
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 0
+ var y int32 = -2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 0
+ var y int32 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 0
+ var y int32 = 0
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 0
+ var y int32 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = 0
+ var y int32 = 2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = 1
+ var y int32 = -2147483648
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 1
+ var y int32 = -2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 1
+ var y int32 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 1
+ var y int32 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 1
+ var y int32 = 1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 1
+ var y int32 = 2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int32 = 2147483647
+ var y int32 = -2147483648
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 2147483647
+ var y int32 = -2147483647
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 2147483647
+ var y int32 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 2147483647
+ var y int32 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 2147483647
+ var y int32 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int32 = 2147483647
+ var y int32 = 2147483647
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+}
+func TestConstFoldCompareuint16(t *testing.T) {
+ {
+ var x uint16 = 0
+ var y uint16 = 0
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint16 = 0
+ var y uint16 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint16 = 0
+ var y uint16 = 65535
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint16 = 1
+ var y uint16 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint16 = 1
+ var y uint16 = 1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint16 = 1
+ var y uint16 = 65535
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint16 = 65535
+ var y uint16 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint16 = 65535
+ var y uint16 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint16 = 65535
+ var y uint16 = 65535
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+}
+func TestConstFoldCompareint16(t *testing.T) {
+ {
+ var x int16 = -32768
+ var y int16 = -32768
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = -32768
+ var y int16 = -32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32768
+ var y int16 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32768
+ var y int16 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32768
+ var y int16 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32768
+ var y int16 = 32766
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32768
+ var y int16 = 32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32767
+ var y int16 = -32768
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = -32767
+ var y int16 = -32767
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = -32767
+ var y int16 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32767
+ var y int16 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32767
+ var y int16 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32767
+ var y int16 = 32766
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -32767
+ var y int16 = 32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -1
+ var y int16 = -32768
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = -1
+ var y int16 = -32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = -1
+ var y int16 = -1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = -1
+ var y int16 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -1
+ var y int16 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -1
+ var y int16 = 32766
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = -1
+ var y int16 = 32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = 0
+ var y int16 = -32768
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 0
+ var y int16 = -32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 0
+ var y int16 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 0
+ var y int16 = 0
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 0
+ var y int16 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = 0
+ var y int16 = 32766
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = 0
+ var y int16 = 32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = 1
+ var y int16 = -32768
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 1
+ var y int16 = -32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 1
+ var y int16 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 1
+ var y int16 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 1
+ var y int16 = 1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 1
+ var y int16 = 32766
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = 1
+ var y int16 = 32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = 32766
+ var y int16 = -32768
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32766
+ var y int16 = -32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32766
+ var y int16 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32766
+ var y int16 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32766
+ var y int16 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32766
+ var y int16 = 32766
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32766
+ var y int16 = 32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int16 = 32767
+ var y int16 = -32768
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32767
+ var y int16 = -32767
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32767
+ var y int16 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32767
+ var y int16 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32767
+ var y int16 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32767
+ var y int16 = 32766
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int16 = 32767
+ var y int16 = 32767
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+}
+func TestConstFoldCompareuint8(t *testing.T) {
+ {
+ var x uint8 = 0
+ var y uint8 = 0
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint8 = 0
+ var y uint8 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint8 = 0
+ var y uint8 = 255
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint8 = 1
+ var y uint8 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint8 = 1
+ var y uint8 = 1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint8 = 1
+ var y uint8 = 255
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x uint8 = 255
+ var y uint8 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint8 = 255
+ var y uint8 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x uint8 = 255
+ var y uint8 = 255
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+}
+func TestConstFoldCompareint8(t *testing.T) {
+ {
+ var x int8 = -128
+ var y int8 = -128
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = -128
+ var y int8 = -127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -128
+ var y int8 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -128
+ var y int8 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -128
+ var y int8 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -128
+ var y int8 = 126
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -128
+ var y int8 = 127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -127
+ var y int8 = -128
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = -127
+ var y int8 = -127
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = -127
+ var y int8 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -127
+ var y int8 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -127
+ var y int8 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -127
+ var y int8 = 126
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -127
+ var y int8 = 127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -1
+ var y int8 = -128
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = -1
+ var y int8 = -127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = -1
+ var y int8 = -1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = -1
+ var y int8 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -1
+ var y int8 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -1
+ var y int8 = 126
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = -1
+ var y int8 = 127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = 0
+ var y int8 = -128
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 0
+ var y int8 = -127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 0
+ var y int8 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 0
+ var y int8 = 0
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 0
+ var y int8 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = 0
+ var y int8 = 126
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = 0
+ var y int8 = 127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = 1
+ var y int8 = -128
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 1
+ var y int8 = -127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 1
+ var y int8 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 1
+ var y int8 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 1
+ var y int8 = 1
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 1
+ var y int8 = 126
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = 1
+ var y int8 = 127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = 126
+ var y int8 = -128
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 126
+ var y int8 = -127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 126
+ var y int8 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 126
+ var y int8 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 126
+ var y int8 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 126
+ var y int8 = 126
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 126
+ var y int8 = 127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if !(x < y) {
+ t.Errorf("!(%d < %d)", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if x >= y {
+ t.Errorf("%d >= %d", x, y)
+ }
+ }
+ {
+ var x int8 = 127
+ var y int8 = -128
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 127
+ var y int8 = -127
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 127
+ var y int8 = -1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 127
+ var y int8 = 0
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 127
+ var y int8 = 1
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 127
+ var y int8 = 126
+ if x == y {
+ t.Errorf("%d == %d", x, y)
+ }
+ if !(x != y) {
+ t.Errorf("!(%d != %d)", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if !(x > y) {
+ t.Errorf("!(%d > %d)", x, y)
+ }
+ if x <= y {
+ t.Errorf("%d <= %d", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+ {
+ var x int8 = 127
+ var y int8 = 127
+ if !(x == y) {
+ t.Errorf("!(%d == %d)", x, y)
+ }
+ if x != y {
+ t.Errorf("%d != %d", x, y)
+ }
+ if x < y {
+ t.Errorf("%d < %d", x, y)
+ }
+ if x > y {
+ t.Errorf("%d > %d", x, y)
+ }
+ if !(x <= y) {
+ t.Errorf("!(%d <= %d)", x, y)
+ }
+ if !(x >= y) {
+ t.Errorf("!(%d >= %d)", x, y)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
new file mode 100644
index 0000000..6e90eb4
--- /dev/null
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -0,0 +1,1185 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "bytes"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+ "fmt"
+ "strings"
+)
+
+// Declaration stack & operations
+
+var externdcl []*Node
+
+func testdclstack() {
+ if !types.IsDclstackValid() {
+ if nerrors != 0 {
+ errorexit()
+ }
+ Fatalf("mark left on the dclstack")
+ }
+}
+
+// redeclare emits a diagnostic about symbol s being redeclared at pos.
+func redeclare(pos src.XPos, s *types.Sym, where string) {
+ if !s.Lastlineno.IsKnown() {
+ pkg := s.Origpkg
+ if pkg == nil {
+ pkg = s.Pkg
+ }
+ yyerrorl(pos, "%v redeclared %s\n"+
+ "\tprevious declaration during import %q", s, where, pkg.Path)
+ } else {
+ prevPos := s.Lastlineno
+
+ // When an import and a declaration collide in separate files,
+ // present the import as the "redeclared", because the declaration
+ // is visible where the import is, but not vice versa.
+ // See issue 4510.
+ if s.Def == nil {
+ pos, prevPos = prevPos, pos
+ }
+
+ yyerrorl(pos, "%v redeclared %s\n"+
+ "\tprevious declaration at %v", s, where, linestr(prevPos))
+ }
+}
+
+var vargen int
+
+// declare individual names - var, typ, const
+
+var declare_typegen int
+
+// declare records that Node n declares symbol n.Sym in the specified
+// declaration context.
+func declare(n *Node, ctxt Class) {
+ if n.isBlank() {
+ return
+ }
+
+ if n.Name == nil {
+ // named OLITERAL needs Name; most OLITERALs don't.
+ n.Name = new(Name)
+ }
+
+ s := n.Sym
+
+ // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
+ if !inimport && !typecheckok && s.Pkg != localpkg {
+ yyerrorl(n.Pos, "cannot declare name %v", s)
+ }
+
+ gen := 0
+ if ctxt == PEXTERN {
+ if s.Name == "init" {
+ yyerrorl(n.Pos, "cannot declare init - must be func")
+ }
+ if s.Name == "main" && s.Pkg.Name == "main" {
+ yyerrorl(n.Pos, "cannot declare main - must be func")
+ }
+ externdcl = append(externdcl, n)
+ } else {
+ if Curfn == nil && ctxt == PAUTO {
+ lineno = n.Pos
+ Fatalf("automatic outside function")
+ }
+ if Curfn != nil && ctxt != PFUNC {
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+ }
+ if n.Op == OTYPE {
+ declare_typegen++
+ gen = declare_typegen
+ } else if n.Op == ONAME && ctxt == PAUTO && !strings.Contains(s.Name, "·") {
+ vargen++
+ gen = vargen
+ }
+ types.Pushdcl(s)
+ n.Name.Curfn = Curfn
+ }
+
+ if ctxt == PAUTO {
+ n.Xoffset = 0
+ }
+
+ if s.Block == types.Block {
+ // functype will print errors about duplicate function arguments.
+ // Don't repeat the error here.
+ if ctxt != PPARAM && ctxt != PPARAMOUT {
+ redeclare(n.Pos, s, "in this block")
+ }
+ }
+
+ s.Block = types.Block
+ s.Lastlineno = lineno
+ s.Def = asTypesNode(n)
+ n.Name.Vargen = int32(gen)
+ n.SetClass(ctxt)
+ if ctxt == PFUNC {
+ n.Sym.SetFunc(true)
+ }
+
+ autoexport(n, ctxt)
+}
+
+func addvar(n *Node, t *types.Type, ctxt Class) {
+ if n == nil || n.Sym == nil || (n.Op != ONAME && n.Op != ONONAME) || t == nil {
+ Fatalf("addvar: n=%v t=%v nil", n, t)
+ }
+
+ n.Op = ONAME
+ declare(n, ctxt)
+ n.Type = t
+}
+
+// declare variables from grammar
+// new_name_list (type | [type] = expr_list)
+func variter(vl []*Node, t *Node, el []*Node) []*Node {
+ var init []*Node
+ doexpr := len(el) > 0
+
+ if len(el) == 1 && len(vl) > 1 {
+ e := el[0]
+ as2 := nod(OAS2, nil, nil)
+ as2.List.Set(vl)
+ as2.Rlist.Set1(e)
+ for _, v := range vl {
+ v.Op = ONAME
+ declare(v, dclcontext)
+ v.Name.Param.Ntype = t
+ v.Name.Defn = as2
+ if Curfn != nil {
+ init = append(init, nod(ODCL, v, nil))
+ }
+ }
+
+ return append(init, as2)
+ }
+
+ nel := len(el)
+ for _, v := range vl {
+ var e *Node
+ if doexpr {
+ if len(el) == 0 {
+ yyerror("assignment mismatch: %d variables but %d values", len(vl), nel)
+ break
+ }
+ e = el[0]
+ el = el[1:]
+ }
+
+ v.Op = ONAME
+ declare(v, dclcontext)
+ v.Name.Param.Ntype = t
+
+ if e != nil || Curfn != nil || v.isBlank() {
+ if Curfn != nil {
+ init = append(init, nod(ODCL, v, nil))
+ }
+ e = nod(OAS, v, e)
+ init = append(init, e)
+ if e.Right != nil {
+ v.Name.Defn = e
+ }
+ }
+ }
+
+ if len(el) != 0 {
+ yyerror("assignment mismatch: %d variables but %d values", len(vl), nel)
+ }
+ return init
+}
+
+// newnoname returns a new ONONAME Node associated with symbol s.
+func newnoname(s *types.Sym) *Node {
+ if s == nil {
+ Fatalf("newnoname nil")
+ }
+ n := nod(ONONAME, nil, nil)
+ n.Sym = s
+ n.Xoffset = 0
+ return n
+}
+
+// newfuncnamel generates a new name node for a function or method.
+// TODO(rsc): Use an ODCLFUNC node instead. See comment in CL 7360.
+func newfuncnamel(pos src.XPos, s *types.Sym) *Node {
+ n := newnamel(pos, s)
+ n.Func = new(Func)
+ n.Func.SetIsHiddenClosure(Curfn != nil)
+ return n
+}
+
+// this generates a new name node for a name
+// being declared.
+func dclname(s *types.Sym) *Node {
+ n := newname(s)
+ n.Op = ONONAME // caller will correct it
+ return n
+}
+
+func typenod(t *types.Type) *Node {
+ return typenodl(src.NoXPos, t)
+}
+
+func typenodl(pos src.XPos, t *types.Type) *Node {
+ // if we copied another type with *t = *u
+ // then t->nod might be out of date, so
+ // check t->nod->type too
+ if asNode(t.Nod) == nil || asNode(t.Nod).Type != t {
+ t.Nod = asTypesNode(nodl(pos, OTYPE, nil, nil))
+ asNode(t.Nod).Type = t
+ asNode(t.Nod).Sym = t.Sym
+ }
+
+ return asNode(t.Nod)
+}
+
+func anonfield(typ *types.Type) *Node {
+ return symfield(nil, typ)
+}
+
+func namedfield(s string, typ *types.Type) *Node {
+ return symfield(lookup(s), typ)
+}
+
+func symfield(s *types.Sym, typ *types.Type) *Node {
+ n := nodSym(ODCLFIELD, nil, s)
+ n.Type = typ
+ return n
+}
+
+// oldname returns the Node that declares symbol s in the current scope.
+// If no such Node currently exists, an ONONAME Node is returned instead.
+// Automatically creates a new closure variable if the referenced symbol was
+// declared in a different (containing) function.
+func oldname(s *types.Sym) *Node {
+ n := asNode(s.Def)
+ if n == nil {
+ // Maybe a top-level declaration will come along later to
+ // define s. resolve will check s.Def again once all input
+ // source has been processed.
+ return newnoname(s)
+ }
+
+ if Curfn != nil && n.Op == ONAME && n.Name.Curfn != nil && n.Name.Curfn != Curfn {
+ // Inner func is referring to var in outer func.
+ //
+ // TODO(rsc): If there is an outer variable x and we
+ // are parsing x := 5 inside the closure, until we get to
+ // the := it looks like a reference to the outer x so we'll
+ // make x a closure variable unnecessarily.
+ c := n.Name.Param.Innermost
+ if c == nil || c.Name.Curfn != Curfn {
+ // Do not have a closure var for the active closure yet; make one.
+ c = newname(s)
+ c.SetClass(PAUTOHEAP)
+ c.Name.SetIsClosureVar(true)
+ c.SetIsDDD(n.IsDDD())
+ c.Name.Defn = n
+
+ // Link into list of active closure variables.
+ // Popped from list in func funcLit.
+ c.Name.Param.Outer = n.Name.Param.Innermost
+ n.Name.Param.Innermost = c
+
+ Curfn.Func.Cvars.Append(c)
+ }
+
+ // return ref to closure var, not original
+ return c
+ }
+
+ return n
+}
+
+// importName is like oldname, but it reports an error if sym is from another package and not exported.
+func importName(sym *types.Sym) *Node {
+ n := oldname(sym)
+ if !types.IsExported(sym.Name) && sym.Pkg != localpkg {
+ n.SetDiag(true)
+ yyerror("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name)
+ }
+ return n
+}
+
+// := declarations
+func colasname(n *Node) bool {
+ switch n.Op {
+ case ONAME,
+ ONONAME,
+ OPACK,
+ OTYPE,
+ OLITERAL:
+ return n.Sym != nil
+ }
+
+ return false
+}
+
+func colasdefn(left []*Node, defn *Node) {
+ for _, n := range left {
+ if n.Sym != nil {
+ n.Sym.SetUniq(true)
+ }
+ }
+
+ var nnew, nerr int
+ for i, n := range left {
+ if n.isBlank() {
+ continue
+ }
+ if !colasname(n) {
+ yyerrorl(defn.Pos, "non-name %v on left side of :=", n)
+ nerr++
+ continue
+ }
+
+ if !n.Sym.Uniq() {
+ yyerrorl(defn.Pos, "%v repeated on left side of :=", n.Sym)
+ n.SetDiag(true)
+ nerr++
+ continue
+ }
+
+ n.Sym.SetUniq(false)
+ if n.Sym.Block == types.Block {
+ continue
+ }
+
+ nnew++
+ n = newname(n.Sym)
+ declare(n, dclcontext)
+ n.Name.Defn = defn
+ defn.Ninit.Append(nod(ODCL, n, nil))
+ left[i] = n
+ }
+
+ if nnew == 0 && nerr == 0 {
+ yyerrorl(defn.Pos, "no new variables on left side of :=")
+ }
+}
+
+// declare the arguments in an
+// interface field declaration.
+func ifacedcl(n *Node) {
+ if n.Op != ODCLFIELD || n.Left == nil {
+ Fatalf("ifacedcl")
+ }
+
+ if n.Sym.IsBlank() {
+ yyerror("methods must have a unique non-blank name")
+ }
+}
+
+// declare the function proper
+// and declare the arguments.
+// called in extern-declaration context
+// returns in auto-declaration context.
+func funchdr(n *Node) {
+ // change the declaration context from extern to auto
+ funcStack = append(funcStack, funcStackEnt{Curfn, dclcontext})
+ Curfn = n
+ dclcontext = PAUTO
+
+ types.Markdcl()
+
+ if n.Func.Nname != nil {
+ funcargs(n.Func.Nname.Name.Param.Ntype)
+ } else if n.Func.Ntype != nil {
+ funcargs(n.Func.Ntype)
+ } else {
+ funcargs2(n.Type)
+ }
+}
+
+func funcargs(nt *Node) {
+ if nt.Op != OTFUNC {
+ Fatalf("funcargs %v", nt.Op)
+ }
+
+ // re-start the variable generation number
+ // we want to use small numbers for the return variables,
+ // so let them have the chunk starting at 1.
+ //
+ // TODO(mdempsky): This is ugly, and only necessary because
+ // esc.go uses Vargen to figure out result parameters' index
+ // within the result tuple.
+ vargen = nt.Rlist.Len()
+
+ // declare the receiver and in arguments.
+ if nt.Left != nil {
+ funcarg(nt.Left, PPARAM)
+ }
+ for _, n := range nt.List.Slice() {
+ funcarg(n, PPARAM)
+ }
+
+ oldvargen := vargen
+ vargen = 0
+
+ // declare the out arguments.
+ gen := nt.List.Len()
+ for _, n := range nt.Rlist.Slice() {
+ if n.Sym == nil {
+ // Name so that escape analysis can track it. ~r stands for 'result'.
+ n.Sym = lookupN("~r", gen)
+ gen++
+ }
+ if n.Sym.IsBlank() {
+ // Give it a name so we can assign to it during return. ~b stands for 'blank'.
+ // The name must be different from ~r above because if you have
+ // func f() (_ int)
+ // func g() int
+ // f is allowed to use a plain 'return' with no arguments, while g is not.
+ // So the two cases must be distinguished.
+ n.Sym = lookupN("~b", gen)
+ gen++
+ }
+
+ funcarg(n, PPARAMOUT)
+ }
+
+ vargen = oldvargen
+}
+
+func funcarg(n *Node, ctxt Class) {
+ if n.Op != ODCLFIELD {
+ Fatalf("funcarg %v", n.Op)
+ }
+ if n.Sym == nil {
+ return
+ }
+
+ n.Right = newnamel(n.Pos, n.Sym)
+ n.Right.Name.Param.Ntype = n.Left
+ n.Right.SetIsDDD(n.IsDDD())
+ declare(n.Right, ctxt)
+
+ vargen++
+ n.Right.Name.Vargen = int32(vargen)
+}
+
+// Same as funcargs, except run over an already constructed TFUNC.
+// This happens during import, where the hidden_fndcl rule has
+// used functype directly to parse the function's type.
+func funcargs2(t *types.Type) {
+ if t.Etype != TFUNC {
+ Fatalf("funcargs2 %v", t)
+ }
+
+ for _, f := range t.Recvs().Fields().Slice() {
+ funcarg2(f, PPARAM)
+ }
+ for _, f := range t.Params().Fields().Slice() {
+ funcarg2(f, PPARAM)
+ }
+ for _, f := range t.Results().Fields().Slice() {
+ funcarg2(f, PPARAMOUT)
+ }
+}
+
+func funcarg2(f *types.Field, ctxt Class) {
+ if f.Sym == nil {
+ return
+ }
+ n := newnamel(f.Pos, f.Sym)
+ f.Nname = asTypesNode(n)
+ n.Type = f.Type
+ n.SetIsDDD(f.IsDDD())
+ declare(n, ctxt)
+}
+
+var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
+
+type funcStackEnt struct {
+ curfn *Node
+ dclcontext Class
+}
+
+// finish the body.
+// called in auto-declaration context.
+// returns in extern-declaration context.
+func funcbody() {
+ // change the declaration context from auto to previous context
+ types.Popdcl()
+ var e funcStackEnt
+ funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
+ Curfn, dclcontext = e.curfn, e.dclcontext
+}
+
+// structs, functions, and methods.
+// they don't belong here, but where do they belong?
+func checkembeddedtype(t *types.Type) {
+ if t == nil {
+ return
+ }
+
+ if t.Sym == nil && t.IsPtr() {
+ t = t.Elem()
+ if t.IsInterface() {
+ yyerror("embedded type cannot be a pointer to interface")
+ }
+ }
+
+ if t.IsPtr() || t.IsUnsafePtr() {
+ yyerror("embedded type cannot be a pointer")
+ } else if t.Etype == TFORW && !t.ForwardType().Embedlineno.IsKnown() {
+ t.ForwardType().Embedlineno = lineno
+ }
+}
+
+func structfield(n *Node) *types.Field {
+ lno := lineno
+ lineno = n.Pos
+
+ if n.Op != ODCLFIELD {
+ Fatalf("structfield: oops %v\n", n)
+ }
+
+ f := types.NewField()
+ f.Pos = n.Pos
+ f.Sym = n.Sym
+
+ if n.Left != nil {
+ n.Left = typecheck(n.Left, ctxType)
+ n.Type = n.Left.Type
+ n.Left = nil
+ }
+
+ f.Type = n.Type
+ if f.Type == nil {
+ f.SetBroke(true)
+ }
+
+ if n.Embedded() {
+ checkembeddedtype(n.Type)
+ f.Embedded = 1
+ } else {
+ f.Embedded = 0
+ }
+
+ switch u := n.Val().U.(type) {
+ case string:
+ f.Note = u
+ default:
+ yyerror("field tag must be a string")
+ case nil:
+ // no-op
+ }
+
+ lineno = lno
+ return f
+}
+
+// checkdupfields emits errors for duplicately named fields or methods in
+// a list of struct or interface types.
+func checkdupfields(what string, fss ...[]*types.Field) {
+ seen := make(map[*types.Sym]bool)
+ for _, fs := range fss {
+ for _, f := range fs {
+ if f.Sym == nil || f.Sym.IsBlank() {
+ continue
+ }
+ if seen[f.Sym] {
+ yyerrorl(f.Pos, "duplicate %s %s", what, f.Sym.Name)
+ continue
+ }
+ seen[f.Sym] = true
+ }
+ }
+}
+
+// convert a parsed id/type list into
+// a type for struct/interface/arglist
+func tostruct(l []*Node) *types.Type {
+ t := types.New(TSTRUCT)
+
+ fields := make([]*types.Field, len(l))
+ for i, n := range l {
+ f := structfield(n)
+ if f.Broke() {
+ t.SetBroke(true)
+ }
+ fields[i] = f
+ }
+ t.SetFields(fields)
+
+ checkdupfields("field", t.FieldSlice())
+
+ if !t.Broke() {
+ checkwidth(t)
+ }
+
+ return t
+}
+
+func tofunargs(l []*Node, funarg types.Funarg) *types.Type {
+ t := types.New(TSTRUCT)
+ t.StructType().Funarg = funarg
+
+ fields := make([]*types.Field, len(l))
+ for i, n := range l {
+ f := structfield(n)
+ f.SetIsDDD(n.IsDDD())
+ if n.Right != nil {
+ n.Right.Type = f.Type
+ f.Nname = asTypesNode(n.Right)
+ }
+ if f.Broke() {
+ t.SetBroke(true)
+ }
+ fields[i] = f
+ }
+ t.SetFields(fields)
+ return t
+}
+
+func tofunargsfield(fields []*types.Field, funarg types.Funarg) *types.Type {
+ t := types.New(TSTRUCT)
+ t.StructType().Funarg = funarg
+ t.SetFields(fields)
+ return t
+}
+
+func interfacefield(n *Node) *types.Field {
+ lno := lineno
+ lineno = n.Pos
+
+ if n.Op != ODCLFIELD {
+ Fatalf("interfacefield: oops %v\n", n)
+ }
+
+ if n.Val().Ctype() != CTxxx {
+ yyerror("interface method cannot have annotation")
+ }
+
+ // MethodSpec = MethodName Signature | InterfaceTypeName .
+ //
+ // If Sym != nil, then Sym is MethodName and Left is Signature.
+ // Otherwise, Left is InterfaceTypeName.
+
+ if n.Left != nil {
+ n.Left = typecheck(n.Left, ctxType)
+ n.Type = n.Left.Type
+ n.Left = nil
+ }
+
+ f := types.NewField()
+ f.Pos = n.Pos
+ f.Sym = n.Sym
+ f.Type = n.Type
+ if f.Type == nil {
+ f.SetBroke(true)
+ }
+
+ lineno = lno
+ return f
+}
+
+func tointerface(l []*Node) *types.Type {
+ if len(l) == 0 {
+ return types.Types[TINTER]
+ }
+ t := types.New(TINTER)
+ var fields []*types.Field
+ for _, n := range l {
+ f := interfacefield(n)
+ if f.Broke() {
+ t.SetBroke(true)
+ }
+ fields = append(fields, f)
+ }
+ t.SetInterface(fields)
+ return t
+}
+
+func fakeRecv() *Node {
+ return anonfield(types.FakeRecvType())
+}
+
+func fakeRecvField() *types.Field {
+ f := types.NewField()
+ f.Type = types.FakeRecvType()
+ return f
+}
+
+// isifacemethod reports whether (field) m is
+// an interface method. Such methods have the
+// special receiver type types.FakeRecvType().
+func isifacemethod(f *types.Type) bool {
+ return f.Recv().Type == types.FakeRecvType()
+}
+
+// turn a parsed function declaration into a type
+func functype(this *Node, in, out []*Node) *types.Type {
+ t := types.New(TFUNC)
+
+ var rcvr []*Node
+ if this != nil {
+ rcvr = []*Node{this}
+ }
+ t.FuncType().Receiver = tofunargs(rcvr, types.FunargRcvr)
+ t.FuncType().Params = tofunargs(in, types.FunargParams)
+ t.FuncType().Results = tofunargs(out, types.FunargResults)
+
+ checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
+
+ if t.Recvs().Broke() || t.Results().Broke() || t.Params().Broke() {
+ t.SetBroke(true)
+ }
+
+ t.FuncType().Outnamed = t.NumResults() > 0 && origSym(t.Results().Field(0).Sym) != nil
+
+ return t
+}
+
+func functypefield(this *types.Field, in, out []*types.Field) *types.Type {
+ t := types.New(TFUNC)
+
+ var rcvr []*types.Field
+ if this != nil {
+ rcvr = []*types.Field{this}
+ }
+ t.FuncType().Receiver = tofunargsfield(rcvr, types.FunargRcvr)
+ t.FuncType().Params = tofunargsfield(in, types.FunargParams)
+ t.FuncType().Results = tofunargsfield(out, types.FunargResults)
+
+ t.FuncType().Outnamed = t.NumResults() > 0 && origSym(t.Results().Field(0).Sym) != nil
+
+ return t
+}
+
+// origSym returns the original symbol written by the user.
+func origSym(s *types.Sym) *types.Sym {
+ if s == nil {
+ return nil
+ }
+
+ if len(s.Name) > 1 && s.Name[0] == '~' {
+ switch s.Name[1] {
+ case 'r': // originally an unnamed result
+ return nil
+ case 'b': // originally the blank identifier _
+ // TODO(mdempsky): Does s.Pkg matter here?
+ return nblank.Sym
+ }
+ return s
+ }
+
+ if strings.HasPrefix(s.Name, ".anon") {
+ // originally an unnamed or _ name (see subr.go: structargs)
+ return nil
+ }
+
+ return s
+}
+
+// methodSym returns the method symbol representing a method name
+// associated with a specific receiver type.
+//
+// Method symbols can be used to distinguish the same method appearing
+// in different method sets. For example, T.M and (*T).M have distinct
+// method symbols.
+//
+// The returned symbol will be marked as a function.
+func methodSym(recv *types.Type, msym *types.Sym) *types.Sym {
+ sym := methodSymSuffix(recv, msym, "")
+ sym.SetFunc(true)
+ return sym
+}
+
+// methodSymSuffix is like methodsym, but allows attaching a
+// distinguisher suffix. To avoid collisions, the suffix must not
+// start with a letter, number, or period.
+func methodSymSuffix(recv *types.Type, msym *types.Sym, suffix string) *types.Sym {
+ if msym.IsBlank() {
+ Fatalf("blank method name")
+ }
+
+ rsym := recv.Sym
+ if recv.IsPtr() {
+ if rsym != nil {
+ Fatalf("declared pointer receiver type: %v", recv)
+ }
+ rsym = recv.Elem().Sym
+ }
+
+ // Find the package the receiver type appeared in. For
+ // anonymous receiver types (i.e., anonymous structs with
+ // embedded fields), use the "go" pseudo-package instead.
+ rpkg := gopkg
+ if rsym != nil {
+ rpkg = rsym.Pkg
+ }
+
+ var b bytes.Buffer
+ if recv.IsPtr() {
+ // The parentheses aren't really necessary, but
+ // they're pretty traditional at this point.
+ fmt.Fprintf(&b, "(%-S)", recv)
+ } else {
+ fmt.Fprintf(&b, "%-S", recv)
+ }
+
+ // A particular receiver type may have multiple non-exported
+ // methods with the same name. To disambiguate them, include a
+ // package qualifier for names that came from a different
+ // package than the receiver type.
+ if !types.IsExported(msym.Name) && msym.Pkg != rpkg {
+ b.WriteString(".")
+ b.WriteString(msym.Pkg.Prefix)
+ }
+
+ b.WriteString(".")
+ b.WriteString(msym.Name)
+ b.WriteString(suffix)
+
+ return rpkg.LookupBytes(b.Bytes())
+}
+
+// Add a method, declared as a function.
+// - msym is the method symbol
+// - t is function type (with receiver)
+// Returns a pointer to the existing or added Field; or nil if there's an error.
+func addmethod(msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
+ if msym == nil {
+ Fatalf("no method symbol")
+ }
+
+ // get parent type sym
+ rf := t.Recv() // ptr to this structure
+ if rf == nil {
+ yyerror("missing receiver")
+ return nil
+ }
+
+ 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 nil
+ }
+ t = t.Elem()
+ }
+
+ switch {
+ case t == nil || t.Broke():
+ // rely on typecheck having complained before
+ case t.Sym == nil:
+ yyerror("invalid receiver type %v (%v is not a defined 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 nil
+ }
+
+ if local && mt.Sym.Pkg != localpkg {
+ yyerror("cannot define new methods on non-local type %v", mt)
+ return nil
+ }
+
+ if msym.IsBlank() {
+ return nil
+ }
+
+ if mt.IsStruct() {
+ for _, f := range mt.Fields().Slice() {
+ if f.Sym == msym {
+ yyerror("type %v has both field and method named %v", mt, msym)
+ f.SetBroke(true)
+ return nil
+ }
+ }
+ }
+
+ for _, f := range mt.Methods().Slice() {
+ if msym.Name != f.Sym.Name {
+ continue
+ }
+ // types.Identical only checks that incoming and result parameters match,
+ // so explicitly check that the receiver parameters match too.
+ if !types.Identical(t, f.Type) || !types.Identical(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
+ }
+
+ f := types.NewField()
+ f.Pos = lineno
+ f.Sym = msym
+ f.Type = t
+ f.SetNointerface(nointerface)
+
+ mt.Methods().Append(f)
+ return f
+}
+
+func funcsymname(s *types.Sym) string {
+ return s.Name + "·f"
+}
+
+// funcsym returns s·f.
+func funcsym(s *types.Sym) *types.Sym {
+ // funcsymsmu here serves to protect not just mutations of funcsyms (below),
+ // but also the package lookup of the func sym name,
+ // since this function gets called concurrently from the backend.
+ // There are no other concurrent package lookups in the backend,
+ // except for the types package, which is protected separately.
+ // Reusing funcsymsmu to also cover this package lookup
+ // avoids a general, broader, expensive package lookup mutex.
+ // Note makefuncsym also does package look-up of func sym names,
+ // but that it is only called serially, from the front end.
+ funcsymsmu.Lock()
+ sf, existed := s.Pkg.LookupOK(funcsymname(s))
+ // Don't export s·f when compiling for dynamic linking.
+ // When dynamically linking, the necessary function
+ // symbols will be created explicitly with makefuncsym.
+ // See the makefuncsym comment for details.
+ if !Ctxt.Flag_dynlink && !existed {
+ funcsyms = append(funcsyms, s)
+ }
+ funcsymsmu.Unlock()
+ return sf
+}
+
+// makefuncsym ensures that s·f is exported.
+// It is only used with -dynlink.
+// When not compiling for dynamic linking,
+// the funcsyms are created as needed by
+// the packages that use them.
+// Normally we emit the s·f stubs as DUPOK syms,
+// but DUPOK doesn't work across shared library boundaries.
+// So instead, when dynamic linking, we only create
+// the s·f stubs in s's package.
+func makefuncsym(s *types.Sym) {
+ if !Ctxt.Flag_dynlink {
+ Fatalf("makefuncsym dynlink")
+ }
+ if s.IsBlank() {
+ return
+ }
+ if compiling_runtime && (s.Name == "getg" || s.Name == "getclosureptr" || s.Name == "getcallerpc" || s.Name == "getcallersp") {
+ // runtime.getg(), getclosureptr(), getcallerpc(), and
+ // getcallersp() are not real functions and so do not
+ // get funcsyms.
+ return
+ }
+ if _, existed := s.Pkg.LookupOK(funcsymname(s)); !existed {
+ funcsyms = append(funcsyms, s)
+ }
+}
+
+// setNodeNameFunc marks a node as a function.
+func setNodeNameFunc(n *Node) {
+ if n.Op != ONAME || n.Class() != Pxxx {
+ Fatalf("expected ONAME/Pxxx node, got %v", n)
+ }
+
+ n.SetClass(PFUNC)
+ n.Sym.SetFunc(true)
+}
+
+func dclfunc(sym *types.Sym, tfn *Node) *Node {
+ if tfn.Op != OTFUNC {
+ Fatalf("expected OTFUNC node, got %v", tfn)
+ }
+
+ fn := nod(ODCLFUNC, nil, nil)
+ fn.Func.Nname = newfuncnamel(lineno, sym)
+ fn.Func.Nname.Name.Defn = fn
+ fn.Func.Nname.Name.Param.Ntype = tfn
+ setNodeNameFunc(fn.Func.Nname)
+ funchdr(fn)
+ fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, ctxType)
+ return fn
+}
+
+type nowritebarrierrecChecker struct {
+ // extraCalls contains extra function calls that may not be
+ // visible during later analysis. It maps from the ODCLFUNC of
+ // the caller to a list of callees.
+ extraCalls map[*Node][]nowritebarrierrecCall
+
+ // curfn is the current function during AST walks.
+ curfn *Node
+}
+
+type nowritebarrierrecCall struct {
+ target *Node // ODCLFUNC of caller or callee
+ lineno src.XPos // line of call
+}
+
+type nowritebarrierrecCallSym struct {
+ target *obj.LSym // LSym of callee
+ lineno src.XPos // line of call
+}
+
+// newNowritebarrierrecChecker creates a nowritebarrierrecChecker. It
+// must be called before transformclosure and walk.
+func newNowritebarrierrecChecker() *nowritebarrierrecChecker {
+ c := &nowritebarrierrecChecker{
+ extraCalls: make(map[*Node][]nowritebarrierrecCall),
+ }
+
+ // Find all systemstack calls and record their targets. In
+ // general, flow analysis can't see into systemstack, but it's
+ // important to handle it for this check, so we model it
+ // directly. This has to happen before transformclosure since
+ // it's a lot harder to work out the argument after.
+ for _, n := range xtop {
+ if n.Op != ODCLFUNC {
+ continue
+ }
+ c.curfn = n
+ inspect(n, c.findExtraCalls)
+ }
+ c.curfn = nil
+ return c
+}
+
+func (c *nowritebarrierrecChecker) findExtraCalls(n *Node) bool {
+ if n.Op != OCALLFUNC {
+ return true
+ }
+ fn := n.Left
+ if fn == nil || fn.Op != ONAME || fn.Class() != PFUNC || fn.Name.Defn == nil {
+ return true
+ }
+ if !isRuntimePkg(fn.Sym.Pkg) || fn.Sym.Name != "systemstack" {
+ return true
+ }
+
+ var callee *Node
+ arg := n.List.First()
+ switch arg.Op {
+ case ONAME:
+ callee = arg.Name.Defn
+ case OCLOSURE:
+ callee = arg.Func.Closure
+ default:
+ Fatalf("expected ONAME or OCLOSURE node, got %+v", arg)
+ }
+ if callee.Op != ODCLFUNC {
+ Fatalf("expected ODCLFUNC node, got %+v", callee)
+ }
+ c.extraCalls[c.curfn] = append(c.extraCalls[c.curfn], nowritebarrierrecCall{callee, n.Pos})
+ return true
+}
+
+// recordCall records a call from ODCLFUNC node "from", to function
+// symbol "to" at position pos.
+//
+// This should be done as late as possible during compilation to
+// capture precise call graphs. The target of the call is an LSym
+// because that's all we know after we start SSA.
+//
+// This can be called concurrently for different from Nodes.
+func (c *nowritebarrierrecChecker) recordCall(from *Node, to *obj.LSym, pos src.XPos) {
+ if from.Op != ODCLFUNC {
+ Fatalf("expected ODCLFUNC, got %v", from)
+ }
+ // We record this information on the *Func so this is
+ // concurrent-safe.
+ fn := from.Func
+ if fn.nwbrCalls == nil {
+ fn.nwbrCalls = new([]nowritebarrierrecCallSym)
+ }
+ *fn.nwbrCalls = append(*fn.nwbrCalls, nowritebarrierrecCallSym{to, pos})
+}
+
+func (c *nowritebarrierrecChecker) check() {
+ // We walk the call graph as late as possible so we can
+ // capture all calls created by lowering, but this means we
+ // only get to see the obj.LSyms of calls. symToFunc lets us
+ // get back to the ODCLFUNCs.
+ symToFunc := make(map[*obj.LSym]*Node)
+ // funcs records the back-edges of the BFS call graph walk. It
+ // maps from the ODCLFUNC of each function that must not have
+ // write barriers to the call that inhibits them. Functions
+ // that are directly marked go:nowritebarrierrec are in this
+ // map with a zero-valued nowritebarrierrecCall. This also
+ // acts as the set of marks for the BFS of the call graph.
+ funcs := make(map[*Node]nowritebarrierrecCall)
+ // q is the queue of ODCLFUNC Nodes to visit in BFS order.
+ var q nodeQueue
+
+ for _, n := range xtop {
+ if n.Op != ODCLFUNC {
+ continue
+ }
+
+ symToFunc[n.Func.lsym] = n
+
+ // Make nowritebarrierrec functions BFS roots.
+ if n.Func.Pragma&Nowritebarrierrec != 0 {
+ funcs[n] = nowritebarrierrecCall{}
+ q.pushRight(n)
+ }
+ // Check go:nowritebarrier functions.
+ if n.Func.Pragma&Nowritebarrier != 0 && n.Func.WBPos.IsKnown() {
+ yyerrorl(n.Func.WBPos, "write barrier prohibited")
+ }
+ }
+
+ // Perform a BFS of the call graph from all
+ // go:nowritebarrierrec functions.
+ enqueue := func(src, target *Node, pos src.XPos) {
+ if target.Func.Pragma&Yeswritebarrierrec != 0 {
+ // Don't flow into this function.
+ return
+ }
+ if _, ok := funcs[target]; ok {
+ // Already found a path to target.
+ return
+ }
+
+ // Record the path.
+ funcs[target] = nowritebarrierrecCall{target: src, lineno: pos}
+ q.pushRight(target)
+ }
+ for !q.empty() {
+ fn := q.popLeft()
+
+ // Check fn.
+ if fn.Func.WBPos.IsKnown() {
+ var err bytes.Buffer
+ call := funcs[fn]
+ for call.target != nil {
+ fmt.Fprintf(&err, "\n\t%v: called by %v", linestr(call.lineno), call.target.Func.Nname)
+ call = funcs[call.target]
+ }
+ yyerrorl(fn.Func.WBPos, "write barrier prohibited by caller; %v%s", fn.Func.Nname, err.String())
+ continue
+ }
+
+ // Enqueue fn's calls.
+ for _, callee := range c.extraCalls[fn] {
+ enqueue(fn, callee.target, callee.lineno)
+ }
+ if fn.Func.nwbrCalls == nil {
+ continue
+ }
+ for _, callee := range *fn.Func.nwbrCalls {
+ target := symToFunc[callee.target]
+ if target != nil {
+ enqueue(fn, target, callee.lineno)
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/dep_test.go b/src/cmd/compile/internal/gc/dep_test.go
new file mode 100644
index 0000000..c1dac93
--- /dev/null
+++ b/src/cmd/compile/internal/gc/dep_test.go
@@ -0,0 +1,25 @@
+// Copyright 2019 The Go Authors. 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 (
+ "internal/testenv"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func TestDeps(t *testing.T) {
+ out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Deps}}", "cmd/compile/internal/gc").Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, dep := range strings.Fields(strings.Trim(string(out), "[]")) {
+ switch dep {
+ case "go/build", "go/token":
+ t.Errorf("undesired dependency on %q", dep)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/dump.go b/src/cmd/compile/internal/gc/dump.go
new file mode 100644
index 0000000..29eb1c1
--- /dev/null
+++ b/src/cmd/compile/internal/gc/dump.go
@@ -0,0 +1,280 @@
+// Copyright 2018 The Go 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 textual dumping of arbitrary data structures
+// for debugging purposes. The code is customized for Node graphs
+// and may be used for an alternative view of the node structure.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "regexp"
+)
+
+// dump is like fdump but prints to stderr.
+func dump(root interface{}, filter string, depth int) {
+ fdump(os.Stderr, root, filter, depth)
+}
+
+// fdump prints the structure of a rooted data structure
+// to w by depth-first traversal of the data structure.
+//
+// The filter parameter is a regular expression. If it is
+// non-empty, only struct fields whose names match filter
+// are printed.
+//
+// The depth parameter controls how deep traversal recurses
+// before it returns (higher value means greater depth).
+// If an empty field filter is given, a good depth default value
+// is 4. A negative depth means no depth limit, which may be fine
+// for small data structures or if there is a non-empty filter.
+//
+// In the output, Node structs are identified by their Op name
+// rather than their type; struct fields with zero values or
+// non-matching field names are omitted, and "…" means recursion
+// depth has been reached or struct fields have been omitted.
+func fdump(w io.Writer, root interface{}, filter string, depth int) {
+ if root == nil {
+ fmt.Fprintln(w, "nil")
+ return
+ }
+
+ if filter == "" {
+ filter = ".*" // default
+ }
+
+ p := dumper{
+ output: w,
+ fieldrx: regexp.MustCompile(filter),
+ ptrmap: make(map[uintptr]int),
+ last: '\n', // force printing of line number on first line
+ }
+
+ p.dump(reflect.ValueOf(root), depth)
+ p.printf("\n")
+}
+
+type dumper struct {
+ output io.Writer
+ fieldrx *regexp.Regexp // field name filter
+ ptrmap map[uintptr]int // ptr -> dump line number
+ lastadr string // last address string printed (for shortening)
+
+ // output
+ 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
+}
+
+// printf is a convenience wrapper.
+func (p *dumper) printf(format string, args ...interface{}) {
+ if _, err := fmt.Fprintf(p, format, args...); err != nil {
+ panic(err)
+ }
+}
+
+// addr returns the (hexadecimal) address string of the object
+// represented by x (or "?" if x is not addressable), with the
+// common prefix between this and the prior address replaced by
+// "0x…" to make it easier to visually match addresses.
+func (p *dumper) addr(x reflect.Value) string {
+ if !x.CanAddr() {
+ return "?"
+ }
+ adr := fmt.Sprintf("%p", x.Addr().Interface())
+ s := adr
+ if i := commonPrefixLen(p.lastadr, adr); i > 0 {
+ s = "0x…" + adr[i:]
+ }
+ p.lastadr = adr
+ return s
+}
+
+// dump prints the contents of x.
+func (p *dumper) dump(x reflect.Value, depth int) {
+ if depth == 0 {
+ p.printf("…")
+ return
+ }
+
+ // special cases
+ switch v := x.Interface().(type) {
+ case Nodes:
+ // unpack Nodes since reflect cannot look inside
+ // due to the unexported field in its struct
+ x = reflect.ValueOf(v.Slice())
+
+ case src.XPos:
+ p.printf("%s", linestr(v))
+ return
+
+ case *types.Node:
+ x = reflect.ValueOf(asNode(v))
+ }
+
+ switch x.Kind() {
+ case reflect.String:
+ p.printf("%q", x.Interface()) // print strings in quotes
+
+ case reflect.Interface:
+ if x.IsNil() {
+ p.printf("nil")
+ return
+ }
+ p.dump(x.Elem(), depth-1)
+
+ case reflect.Ptr:
+ if x.IsNil() {
+ p.printf("nil")
+ return
+ }
+
+ p.printf("*")
+ ptr := x.Pointer()
+ if line, exists := p.ptrmap[ptr]; exists {
+ p.printf("(@%d)", line)
+ return
+ }
+ p.ptrmap[ptr] = p.line
+ p.dump(x.Elem(), depth) // don't count pointer indirection towards depth
+
+ 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), depth-1)
+ p.printf("\n")
+ }
+ p.indent--
+ }
+ p.printf("}")
+
+ case reflect.Struct:
+ typ := x.Type()
+
+ isNode := false
+ if n, ok := x.Interface().(Node); ok {
+ isNode = true
+ p.printf("%s %s {", n.Op.String(), p.addr(x))
+ } else {
+ p.printf("%s {", typ)
+ }
+ p.indent++
+
+ first := true
+ omitted := false
+ 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; types.IsExported(name) {
+ if !p.fieldrx.MatchString(name) {
+ omitted = true
+ continue // field name not selected by filter
+ }
+
+ // special cases
+ if isNode && name == "Op" {
+ omitted = true
+ continue // Op field already printed for Nodes
+ }
+ x := x.Field(i)
+ if isZeroVal(x) {
+ omitted = true
+ continue // exclude zero-valued fields
+ }
+ if n, ok := x.Interface().(Nodes); ok && n.Len() == 0 {
+ omitted = true
+ continue // exclude empty Nodes slices
+ }
+
+ if first {
+ p.printf("\n")
+ first = false
+ }
+ p.printf("%s: ", name)
+ p.dump(x, depth-1)
+ p.printf("\n")
+ }
+ }
+ if omitted {
+ p.printf("…\n")
+ }
+
+ p.indent--
+ p.printf("}")
+
+ default:
+ p.printf("%v", x.Interface())
+ }
+}
+
+func isZeroVal(x reflect.Value) bool {
+ switch x.Kind() {
+ case reflect.Bool:
+ return !x.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return x.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return x.Uint() == 0
+ case reflect.String:
+ return x.String() == ""
+ case reflect.Interface, reflect.Ptr, reflect.Slice:
+ return x.IsNil()
+ }
+ return false
+}
+
+func commonPrefixLen(a, b string) (i int) {
+ for i < len(a) && i < len(b) && a[i] == b[i] {
+ i++
+ }
+ return
+}
diff --git a/src/cmd/compile/internal/gc/dwinl.go b/src/cmd/compile/internal/gc/dwinl.go
new file mode 100644
index 0000000..31d0768
--- /dev/null
+++ b/src/cmd/compile/internal/gc/dwinl.go
@@ -0,0 +1,450 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/internal/dwarf"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+ "fmt"
+ "strings"
+)
+
+// To identify variables by original source position.
+type varPos struct {
+ DeclName string
+ DeclFile string
+ DeclLine uint
+ DeclCol uint
+}
+
+// This is the main entry point for collection of raw material to
+// drive generation of DWARF "inlined subroutine" DIEs. See proposal
+// 22080 for more details and background info.
+func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
+ var inlcalls dwarf.InlCalls
+
+ if Debug_gendwarfinl != 0 {
+ Ctxt.Logf("assembling DWARF inlined routine info for %v\n", fnsym.Name)
+ }
+
+ // This maps inline index (from Ctxt.InlTree) to index in inlcalls.Calls
+ imap := make(map[int]int)
+
+ // Walk progs to build up the InlCalls data structure
+ var prevpos src.XPos
+ for p := fnsym.Func().Text; p != nil; p = p.Link {
+ if p.Pos == prevpos {
+ continue
+ }
+ ii := posInlIndex(p.Pos)
+ if ii >= 0 {
+ insertInlCall(&inlcalls, ii, imap)
+ }
+ prevpos = p.Pos
+ }
+
+ // This is used to partition DWARF vars by inline index. Vars not
+ // produced by the inliner will wind up in the vmap[0] entry.
+ vmap := make(map[int32][]*dwarf.Var)
+
+ // Now walk the dwarf vars and partition them based on whether they
+ // were produced by the inliner (dwv.InlIndex > 0) or were original
+ // vars/params from the function (dwv.InlIndex == 0).
+ for _, dwv := range dwVars {
+
+ vmap[dwv.InlIndex] = append(vmap[dwv.InlIndex], dwv)
+
+ // Zero index => var was not produced by an inline
+ if dwv.InlIndex == 0 {
+ continue
+ }
+
+ // Look up index in our map, then tack the var in question
+ // onto the vars list for the correct inlined call.
+ ii := int(dwv.InlIndex) - 1
+ idx, ok := imap[ii]
+ if !ok {
+ // We can occasionally encounter a var produced by the
+ // inliner for which there is no remaining prog; add a new
+ // entry to the call list in this scenario.
+ idx = insertInlCall(&inlcalls, ii, imap)
+ }
+ inlcalls.Calls[idx].InlVars =
+ append(inlcalls.Calls[idx].InlVars, dwv)
+ }
+
+ // Post process the map above to assign child indices to vars.
+ //
+ // A given variable is treated differently depending on whether it
+ // is part of the top-level function (ii == 0) or if it was
+ // produced as a result of an inline (ii != 0).
+ //
+ // If a variable was not produced by an inline and its containing
+ // function was not inlined, then we just assign an ordering of
+ // based on variable name.
+ //
+ // If a variable was not produced by an inline and its containing
+ // function was inlined, then we need to assign a child index
+ // based on the order of vars in the abstract function (in
+ // addition, those vars that don't appear in the abstract
+ // function, such as "~r1", are flagged as such).
+ //
+ // If a variable was produced by an inline, then we locate it in
+ // the pre-inlining decls for the target function and assign child
+ // index accordingly.
+ for ii, sl := range vmap {
+ var m map[varPos]int
+ if ii == 0 {
+ if !fnsym.WasInlined() {
+ for j, v := range sl {
+ v.ChildIndex = int32(j)
+ }
+ continue
+ }
+ m = makePreinlineDclMap(fnsym)
+ } else {
+ ifnlsym := Ctxt.InlTree.InlinedFunction(int(ii - 1))
+ m = makePreinlineDclMap(ifnlsym)
+ }
+
+ // Here we assign child indices to variables based on
+ // pre-inlined decls, and set the "IsInAbstract" flag
+ // appropriately. In addition: parameter and local variable
+ // names are given "middle dot" version numbers as part of the
+ // writing them out to export data (see issue 4326). If DWARF
+ // inlined routine generation is turned on, we want to undo
+ // this versioning, since DWARF variables in question will be
+ // parented by the inlined routine and not the top-level
+ // caller.
+ synthCount := len(m)
+ for _, v := range sl {
+ canonName := unversion(v.Name)
+ vp := varPos{
+ DeclName: canonName,
+ DeclFile: v.DeclFile,
+ DeclLine: v.DeclLine,
+ DeclCol: v.DeclCol,
+ }
+ synthesized := strings.HasPrefix(v.Name, "~r") || canonName == "_" || strings.HasPrefix(v.Name, "~b")
+ if idx, found := m[vp]; found {
+ v.ChildIndex = int32(idx)
+ v.IsInAbstract = !synthesized
+ v.Name = canonName
+ } else {
+ // Variable can't be found in the pre-inline dcl list.
+ // In the top-level case (ii=0) this can happen
+ // because a composite variable was split into pieces,
+ // and we're looking at a piece. We can also see
+ // return temps (~r%d) that were created during
+ // lowering, or unnamed params ("_").
+ v.ChildIndex = int32(synthCount)
+ synthCount++
+ }
+ }
+ }
+
+ // Make a second pass through the progs to compute PC ranges for
+ // the various inlined calls.
+ start := int64(-1)
+ curii := -1
+ var prevp *obj.Prog
+ for p := fnsym.Func().Text; p != nil; prevp, p = p, p.Link {
+ if prevp != nil && p.Pos == prevp.Pos {
+ continue
+ }
+ ii := posInlIndex(p.Pos)
+ if ii == curii {
+ continue
+ }
+ // Close out the current range
+ if start != -1 {
+ addRange(inlcalls.Calls, start, p.Pc, curii, imap)
+ }
+ // Begin new range
+ start = p.Pc
+ curii = ii
+ }
+ if start != -1 {
+ addRange(inlcalls.Calls, start, fnsym.Size, curii, imap)
+ }
+
+ // Issue 33188: if II foo is a child of II bar, then ensure that
+ // bar's ranges include the ranges of foo (the loop above will produce
+ // disjoint ranges).
+ for k, c := range inlcalls.Calls {
+ if c.Root {
+ unifyCallRanges(inlcalls, k)
+ }
+ }
+
+ // Debugging
+ if Debug_gendwarfinl != 0 {
+ dumpInlCalls(inlcalls)
+ dumpInlVars(dwVars)
+ }
+
+ // Perform a consistency check on inlined routine PC ranges
+ // produced by unifyCallRanges above. In particular, complain in
+ // cases where you have A -> B -> C (e.g. C is inlined into B, and
+ // B is inlined into A) and the ranges for B are not enclosed
+ // within the ranges for A, or C within B.
+ for k, c := range inlcalls.Calls {
+ if c.Root {
+ checkInlCall(fnsym.Name, inlcalls, fnsym.Size, k, -1)
+ }
+ }
+
+ return inlcalls
+}
+
+// Secondary hook for DWARF inlined subroutine generation. This is called
+// late in the compilation when it is determined that we need an
+// abstract function DIE for an inlined routine imported from a
+// previously compiled package.
+func genAbstractFunc(fn *obj.LSym) {
+ ifn := Ctxt.DwFixups.GetPrecursorFunc(fn)
+ if ifn == nil {
+ Ctxt.Diag("failed to locate precursor fn for %v", fn)
+ return
+ }
+ if Debug_gendwarfinl != 0 {
+ Ctxt.Logf("DwarfAbstractFunc(%v)\n", fn.Name)
+ }
+ Ctxt.DwarfAbstractFunc(ifn, fn, myimportpath)
+}
+
+// Undo any versioning performed when a name was written
+// out as part of export data.
+func unversion(name string) string {
+ if i := strings.Index(name, "·"); i > 0 {
+ name = name[:i]
+ }
+ return name
+}
+
+// Given a function that was inlined as part of the compilation, dig
+// up the pre-inlining DCL list for the function and create a map that
+// supports lookup of pre-inline dcl index, based on variable
+// position/name. NB: the recipe for computing variable pos/file/line
+// needs to be kept in sync with the similar code in gc.createSimpleVars
+// and related functions.
+func makePreinlineDclMap(fnsym *obj.LSym) map[varPos]int {
+ dcl := preInliningDcls(fnsym)
+ m := make(map[varPos]int)
+ for i, n := range dcl {
+ pos := Ctxt.InnermostPos(n.Pos)
+ vp := varPos{
+ DeclName: unversion(n.Sym.Name),
+ DeclFile: pos.RelFilename(),
+ DeclLine: pos.RelLine(),
+ DeclCol: pos.Col(),
+ }
+ if _, found := m[vp]; found {
+ // We can see collisions (variables with the same name/file/line/col) in obfuscated or machine-generated code -- see issue 44378 for an example. Skip duplicates in such cases, since it is unlikely that a human will be debugging such code.
+ continue
+ }
+ m[vp] = i
+ }
+ return m
+}
+
+func insertInlCall(dwcalls *dwarf.InlCalls, inlIdx int, imap map[int]int) int {
+ callIdx, found := imap[inlIdx]
+ if found {
+ return callIdx
+ }
+
+ // Haven't seen this inline yet. Visit parent of inline if there
+ // is one. We do this first so that parents appear before their
+ // children in the resulting table.
+ parCallIdx := -1
+ parInlIdx := Ctxt.InlTree.Parent(inlIdx)
+ if parInlIdx >= 0 {
+ parCallIdx = insertInlCall(dwcalls, parInlIdx, imap)
+ }
+
+ // Create new entry for this inline
+ inlinedFn := Ctxt.InlTree.InlinedFunction(inlIdx)
+ callXPos := Ctxt.InlTree.CallPos(inlIdx)
+ absFnSym := Ctxt.DwFixups.AbsFuncDwarfSym(inlinedFn)
+ pb := Ctxt.PosTable.Pos(callXPos).Base()
+ callFileSym := Ctxt.Lookup(pb.SymFilename())
+ ic := dwarf.InlCall{
+ InlIndex: inlIdx,
+ CallFile: callFileSym,
+ CallLine: uint32(callXPos.Line()),
+ AbsFunSym: absFnSym,
+ Root: parCallIdx == -1,
+ }
+ dwcalls.Calls = append(dwcalls.Calls, ic)
+ callIdx = len(dwcalls.Calls) - 1
+ imap[inlIdx] = callIdx
+
+ if parCallIdx != -1 {
+ // Add this inline to parent's child list
+ dwcalls.Calls[parCallIdx].Children = append(dwcalls.Calls[parCallIdx].Children, callIdx)
+ }
+
+ return callIdx
+}
+
+// Given a src.XPos, return its associated inlining index if it
+// corresponds to something created as a result of an inline, or -1 if
+// there is no inline info. Note that the index returned will refer to
+// the deepest call in the inlined stack, e.g. if you have "A calls B
+// calls C calls D" and all three callees are inlined (B, C, and D),
+// the index for a node from the inlined body of D will refer to the
+// call to D from C. Whew.
+func posInlIndex(xpos src.XPos) int {
+ pos := Ctxt.PosTable.Pos(xpos)
+ if b := pos.Base(); b != nil {
+ ii := b.InliningIndex()
+ if ii >= 0 {
+ return ii
+ }
+ }
+ return -1
+}
+
+func addRange(calls []dwarf.InlCall, start, end int64, ii int, imap map[int]int) {
+ if start == -1 {
+ panic("bad range start")
+ }
+ if end == -1 {
+ panic("bad range end")
+ }
+ if ii == -1 {
+ return
+ }
+ if start == end {
+ return
+ }
+ // Append range to correct inlined call
+ callIdx, found := imap[ii]
+ if !found {
+ Fatalf("can't find inlIndex %d in imap for prog at %d\n", ii, start)
+ }
+ call := &calls[callIdx]
+ call.Ranges = append(call.Ranges, dwarf.Range{Start: start, End: end})
+}
+
+func dumpInlCall(inlcalls dwarf.InlCalls, idx, ilevel int) {
+ for i := 0; i < ilevel; i++ {
+ Ctxt.Logf(" ")
+ }
+ ic := inlcalls.Calls[idx]
+ callee := Ctxt.InlTree.InlinedFunction(ic.InlIndex)
+ Ctxt.Logf(" %d: II:%d (%s) V: (", idx, ic.InlIndex, callee.Name)
+ for _, f := range ic.InlVars {
+ Ctxt.Logf(" %v", f.Name)
+ }
+ Ctxt.Logf(" ) C: (")
+ for _, k := range ic.Children {
+ Ctxt.Logf(" %v", k)
+ }
+ Ctxt.Logf(" ) R:")
+ for _, r := range ic.Ranges {
+ Ctxt.Logf(" [%d,%d)", r.Start, r.End)
+ }
+ Ctxt.Logf("\n")
+ for _, k := range ic.Children {
+ dumpInlCall(inlcalls, k, ilevel+1)
+ }
+
+}
+
+func dumpInlCalls(inlcalls dwarf.InlCalls) {
+ for k, c := range inlcalls.Calls {
+ if c.Root {
+ dumpInlCall(inlcalls, k, 0)
+ }
+ }
+}
+
+func dumpInlVars(dwvars []*dwarf.Var) {
+ for i, dwv := range dwvars {
+ typ := "local"
+ if dwv.Abbrev == dwarf.DW_ABRV_PARAM_LOCLIST || dwv.Abbrev == dwarf.DW_ABRV_PARAM {
+ typ = "param"
+ }
+ ia := 0
+ if dwv.IsInAbstract {
+ ia = 1
+ }
+ Ctxt.Logf("V%d: %s CI:%d II:%d IA:%d %s\n", i, dwv.Name, dwv.ChildIndex, dwv.InlIndex-1, ia, typ)
+ }
+}
+
+func rangesContains(par []dwarf.Range, rng dwarf.Range) (bool, string) {
+ for _, r := range par {
+ if rng.Start >= r.Start && rng.End <= r.End {
+ return true, ""
+ }
+ }
+ msg := fmt.Sprintf("range [%d,%d) not contained in {", rng.Start, rng.End)
+ for _, r := range par {
+ msg += fmt.Sprintf(" [%d,%d)", r.Start, r.End)
+ }
+ msg += " }"
+ return false, msg
+}
+
+func rangesContainsAll(parent, child []dwarf.Range) (bool, string) {
+ for _, r := range child {
+ c, m := rangesContains(parent, r)
+ if !c {
+ return false, m
+ }
+ }
+ return true, ""
+}
+
+// checkInlCall verifies that the PC ranges for inline info 'idx' are
+// enclosed/contained within the ranges of its parent inline (or if
+// this is a root/toplevel inline, checks that the ranges fall within
+// the extent of the top level function). A panic is issued if a
+// malformed range is found.
+func checkInlCall(funcName string, inlCalls dwarf.InlCalls, funcSize int64, idx, parentIdx int) {
+
+ // Callee
+ ic := inlCalls.Calls[idx]
+ callee := Ctxt.InlTree.InlinedFunction(ic.InlIndex).Name
+ calleeRanges := ic.Ranges
+
+ // Caller
+ caller := funcName
+ parentRanges := []dwarf.Range{dwarf.Range{Start: int64(0), End: funcSize}}
+ if parentIdx != -1 {
+ pic := inlCalls.Calls[parentIdx]
+ caller = Ctxt.InlTree.InlinedFunction(pic.InlIndex).Name
+ parentRanges = pic.Ranges
+ }
+
+ // Callee ranges contained in caller ranges?
+ c, m := rangesContainsAll(parentRanges, calleeRanges)
+ if !c {
+ Fatalf("** malformed inlined routine range in %s: caller %s callee %s II=%d %s\n", funcName, caller, callee, idx, m)
+ }
+
+ // Now visit kids
+ for _, k := range ic.Children {
+ checkInlCall(funcName, inlCalls, funcSize, k, idx)
+ }
+}
+
+// unifyCallRanges ensures that the ranges for a given inline
+// transitively include all of the ranges for its child inlines.
+func unifyCallRanges(inlcalls dwarf.InlCalls, idx int) {
+ ic := &inlcalls.Calls[idx]
+ for _, childIdx := range ic.Children {
+ // First make sure child ranges are unified.
+ unifyCallRanges(inlcalls, childIdx)
+
+ // Then merge child ranges into ranges for this inline.
+ cic := inlcalls.Calls[childIdx]
+ ic.Ranges = dwarf.MergeRanges(ic.Ranges, cic.Ranges)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/embed.go b/src/cmd/compile/internal/gc/embed.go
new file mode 100644
index 0000000..f45796c
--- /dev/null
+++ b/src/cmd/compile/internal/gc/embed.go
@@ -0,0 +1,256 @@
+// Copyright 2020 The Go Authors. 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/syntax"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "encoding/json"
+ "io/ioutil"
+ "log"
+ "path"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+var embedlist []*Node
+
+var embedCfg struct {
+ Patterns map[string][]string
+ Files map[string]string
+}
+
+func readEmbedCfg(file string) {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ log.Fatalf("-embedcfg: %v", err)
+ }
+ if err := json.Unmarshal(data, &embedCfg); err != nil {
+ log.Fatalf("%s: %v", file, err)
+ }
+ if embedCfg.Patterns == nil {
+ log.Fatalf("%s: invalid embedcfg: missing Patterns", file)
+ }
+ if embedCfg.Files == nil {
+ log.Fatalf("%s: invalid embedcfg: missing Files", file)
+ }
+}
+
+const (
+ embedUnknown = iota
+ embedBytes
+ embedString
+ embedFiles
+)
+
+func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []PragmaEmbed) {
+ haveEmbed := false
+ for _, decl := range p.file.DeclList {
+ imp, ok := decl.(*syntax.ImportDecl)
+ if !ok {
+ // imports always come first
+ break
+ }
+ path, _ := strconv.Unquote(imp.Path.Value)
+ if path == "embed" {
+ haveEmbed = true
+ break
+ }
+ }
+
+ pos := embeds[0].Pos
+ if !haveEmbed {
+ p.yyerrorpos(pos, "invalid go:embed: missing import \"embed\"")
+ return
+ }
+ if len(names) > 1 {
+ p.yyerrorpos(pos, "go:embed cannot apply to multiple vars")
+ return
+ }
+ if len(exprs) > 0 {
+ p.yyerrorpos(pos, "go:embed cannot apply to var with initializer")
+ return
+ }
+ if typ == nil {
+ // Should not happen, since len(exprs) == 0 now.
+ p.yyerrorpos(pos, "go:embed cannot apply to var without type")
+ return
+ }
+ if dclcontext != PEXTERN {
+ p.yyerrorpos(pos, "go:embed cannot apply to var inside func")
+ return
+ }
+
+ var list []irEmbed
+ for _, e := range embeds {
+ list = append(list, irEmbed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns})
+ }
+ v := names[0]
+ v.Name.Param.SetEmbedList(list)
+ embedlist = append(embedlist, v)
+}
+
+func embedFileList(v *Node, kind int) []string {
+ // Build list of files to store.
+ have := make(map[string]bool)
+ var list []string
+ for _, e := range v.Name.Param.EmbedList() {
+ for _, pattern := range e.Patterns {
+ files, ok := embedCfg.Patterns[pattern]
+ if !ok {
+ yyerrorl(e.Pos, "invalid go:embed: build system did not map pattern: %s", pattern)
+ }
+ for _, file := range files {
+ if embedCfg.Files[file] == "" {
+ yyerrorl(e.Pos, "invalid go:embed: build system did not map file: %s", file)
+ continue
+ }
+ if !have[file] {
+ have[file] = true
+ list = append(list, file)
+ }
+ if kind == embedFiles {
+ for dir := path.Dir(file); dir != "." && !have[dir]; dir = path.Dir(dir) {
+ have[dir] = true
+ list = append(list, dir+"/")
+ }
+ }
+ }
+ }
+ }
+ sort.Slice(list, func(i, j int) bool {
+ return embedFileLess(list[i], list[j])
+ })
+
+ if kind == embedString || kind == embedBytes {
+ if len(list) > 1 {
+ yyerrorl(v.Pos, "invalid go:embed: multiple files for type %v", v.Type)
+ return nil
+ }
+ }
+
+ return list
+}
+
+// embedKind determines the kind of embedding variable.
+func embedKind(typ *types.Type) int {
+ if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && myimportpath == "embed")) {
+ return embedFiles
+ }
+ if typ.Etype == types.TSTRING {
+ return embedString
+ }
+ if typ.Etype == types.TSLICE && typ.Elem().Etype == types.TUINT8 {
+ return embedBytes
+ }
+ return embedUnknown
+}
+
+func embedFileNameSplit(name string) (dir, elem string, isDir bool) {
+ if name[len(name)-1] == '/' {
+ isDir = true
+ name = name[:len(name)-1]
+ }
+ i := len(name) - 1
+ for i >= 0 && name[i] != '/' {
+ i--
+ }
+ if i < 0 {
+ return ".", name, isDir
+ }
+ return name[:i], name[i+1:], isDir
+}
+
+// embedFileLess implements the sort order for a list of embedded files.
+// See the comment inside ../../../../embed/embed.go's Files struct for rationale.
+func embedFileLess(x, y string) bool {
+ xdir, xelem, _ := embedFileNameSplit(x)
+ ydir, yelem, _ := embedFileNameSplit(y)
+ return xdir < ydir || xdir == ydir && xelem < yelem
+}
+
+func dumpembeds() {
+ for _, v := range embedlist {
+ initEmbed(v)
+ }
+}
+
+// initEmbed emits the init data for a //go:embed variable,
+// which is either a string, a []byte, or an embed.FS.
+func initEmbed(v *Node) {
+ commentPos := v.Name.Param.EmbedList()[0].Pos
+ if !langSupported(1, 16, localpkg) {
+ lno := lineno
+ lineno = commentPos
+ yyerrorv("go1.16", "go:embed")
+ lineno = lno
+ return
+ }
+ if embedCfg.Patterns == nil {
+ yyerrorl(commentPos, "invalid go:embed: build system did not supply embed configuration")
+ return
+ }
+ kind := embedKind(v.Type)
+ if kind == embedUnknown {
+ yyerrorl(v.Pos, "go:embed cannot apply to var of type %v", v.Type)
+ return
+ }
+
+ files := embedFileList(v, kind)
+ switch kind {
+ case embedString, embedBytes:
+ file := files[0]
+ fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], kind == embedString, nil)
+ if err != nil {
+ yyerrorl(v.Pos, "embed %s: %v", file, err)
+ }
+ sym := v.Sym.Linksym()
+ off := 0
+ off = dsymptr(sym, off, fsym, 0) // data string
+ off = duintptr(sym, off, uint64(size)) // len
+ if kind == embedBytes {
+ duintptr(sym, off, uint64(size)) // cap for slice
+ }
+
+ case embedFiles:
+ slicedata := Ctxt.Lookup(`"".` + v.Sym.Name + `.files`)
+ off := 0
+ // []files pointed at by Files
+ off = dsymptr(slicedata, off, slicedata, 3*Widthptr) // []file, pointing just past slice
+ off = duintptr(slicedata, off, uint64(len(files)))
+ off = duintptr(slicedata, off, uint64(len(files)))
+
+ // embed/embed.go type file is:
+ // name string
+ // data string
+ // hash [16]byte
+ // Emit one of these per file in the set.
+ const hashSize = 16
+ hash := make([]byte, hashSize)
+ for _, file := range files {
+ off = dsymptr(slicedata, off, stringsym(v.Pos, file), 0) // file string
+ off = duintptr(slicedata, off, uint64(len(file)))
+ if strings.HasSuffix(file, "/") {
+ // entry for directory - no data
+ off = duintptr(slicedata, off, 0)
+ off = duintptr(slicedata, off, 0)
+ off += hashSize
+ } else {
+ fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], true, hash)
+ if err != nil {
+ yyerrorl(v.Pos, "embed %s: %v", file, err)
+ }
+ off = dsymptr(slicedata, off, fsym, 0) // data string
+ off = duintptr(slicedata, off, uint64(size))
+ off = int(slicedata.WriteBytes(Ctxt, int64(off), hash))
+ }
+ }
+ ggloblsym(slicedata, int32(off), obj.RODATA|obj.LOCAL)
+ sym := v.Sym.Linksym()
+ dsymptr(sym, 0, slicedata, 0)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
new file mode 100644
index 0000000..6f328ab
--- /dev/null
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -0,0 +1,472 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "fmt"
+)
+
+func escapes(all []*Node) {
+ visitBottomUp(all, escapeFuncs)
+}
+
+const (
+ EscFuncUnknown = 0 + iota
+ EscFuncPlanned
+ EscFuncStarted
+ EscFuncTagged
+)
+
+func min8(a, b int8) int8 {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func max8(a, b int8) int8 {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+const (
+ EscUnknown = iota
+ EscNone // Does not escape to heap, result, or parameters.
+ EscHeap // Reachable from the heap
+ EscNever // By construction will not escape.
+)
+
+// funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way.
+func funcSym(fn *Node) *types.Sym {
+ if fn == nil || fn.Func.Nname == nil {
+ return nil
+ }
+ return fn.Func.Nname.Sym
+}
+
+// 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 Node
+ nonlooping Node
+)
+
+func isSliceSelfAssign(dst, src *Node) bool {
+ // Detect the following special case.
+ //
+ // func (b *Buffer) Foo() {
+ // n, m := ...
+ // b.buf = b.buf[n:m]
+ // }
+ //
+ // This assignment is a no-op for escape analysis,
+ // it does not store any new pointers into b that were not already there.
+ // However, without this special case b will escape, because we assign to OIND/ODOTPTR.
+ // Here we assume that the statement will not contain calls,
+ // that is, that order will move any calls to init.
+ // Otherwise base ONAME value could change between the moments
+ // when we evaluate it for dst and for src.
+
+ // dst is ONAME dereference.
+ if dst.Op != ODEREF && dst.Op != ODOTPTR || dst.Left.Op != ONAME {
+ return false
+ }
+ // src is a slice operation.
+ switch src.Op {
+ case OSLICE, OSLICE3, OSLICESTR:
+ // OK.
+ case OSLICEARR, OSLICE3ARR:
+ // Since arrays are embedded into containing object,
+ // slice of non-pointer array will introduce a new pointer into b that was not already there
+ // (pointer to b itself). After such assignment, if b contents escape,
+ // b escapes as well. If we ignore such OSLICEARR, we will conclude
+ // that b does not escape when b contents do.
+ //
+ // Pointer to an array is OK since it's not stored inside b directly.
+ // For slicing an array (not pointer to array), there is an implicit OADDR.
+ // We check that to determine non-pointer array slicing.
+ if src.Left.Op == OADDR {
+ return false
+ }
+ default:
+ return false
+ }
+ // slice is applied to ONAME dereference.
+ if src.Left.Op != ODEREF && src.Left.Op != ODOTPTR || src.Left.Left.Op != ONAME {
+ return false
+ }
+ // dst and src reference the same base ONAME.
+ return dst.Left == src.Left.Left
+}
+
+// isSelfAssign reports whether assignment from src to dst can
+// be ignored by the escape analysis as it's effectively a self-assignment.
+func isSelfAssign(dst, src *Node) bool {
+ if isSliceSelfAssign(dst, src) {
+ return true
+ }
+
+ // Detect trivial assignments that assign back to the same object.
+ //
+ // It covers these cases:
+ // val.x = val.y
+ // val.x[i] = val.y[j]
+ // val.x1.x2 = val.x1.y2
+ // ... etc
+ //
+ // These assignments do not change assigned object lifetime.
+
+ if dst == nil || src == nil || dst.Op != src.Op {
+ return false
+ }
+
+ switch dst.Op {
+ case ODOT, ODOTPTR:
+ // Safe trailing accessors that are permitted to differ.
+ case OINDEX:
+ if mayAffectMemory(dst.Right) || mayAffectMemory(src.Right) {
+ return false
+ }
+ default:
+ return false
+ }
+
+ // The expression prefix must be both "safe" and identical.
+ return samesafeexpr(dst.Left, src.Left)
+}
+
+// mayAffectMemory reports whether evaluation of n may affect the program's
+// memory state. If the expression can't affect memory state, then it can be
+// safely ignored by the escape analysis.
+func mayAffectMemory(n *Node) bool {
+ // We may want to use a list of "memory safe" ops instead of generally
+ // "side-effect free", which would include all calls and other ops that can
+ // allocate or change global state. For now, it's safer to start with the latter.
+ //
+ // We're ignoring things like division by zero, index out of range,
+ // and nil pointer dereference here.
+ switch n.Op {
+ case ONAME, OCLOSUREVAR, OLITERAL:
+ return false
+
+ // Left+Right group.
+ case OINDEX, OADD, OSUB, OOR, OXOR, OMUL, OLSH, ORSH, OAND, OANDNOT, ODIV, OMOD:
+ return mayAffectMemory(n.Left) || mayAffectMemory(n.Right)
+
+ // Left group.
+ case ODOT, ODOTPTR, ODEREF, OCONVNOP, OCONV, OLEN, OCAP,
+ ONOT, OBITNOT, OPLUS, ONEG, OALIGNOF, OOFFSETOF, OSIZEOF:
+ return mayAffectMemory(n.Left)
+
+ default:
+ return true
+ }
+}
+
+// heapAllocReason returns the reason the given Node must be heap
+// allocated, or the empty string if it doesn't.
+func heapAllocReason(n *Node) string {
+ if n.Type == nil {
+ return ""
+ }
+
+ // Parameters are always passed via the stack.
+ if n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) {
+ return ""
+ }
+
+ if n.Type.Width > maxStackVarSize {
+ return "too large for stack"
+ }
+
+ if (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize {
+ return "too large for stack"
+ }
+
+ if n.Op == OCLOSURE && closureType(n).Size() >= maxImplicitStackVarSize {
+ return "too large for stack"
+ }
+ if n.Op == OCALLPART && partialCallType(n).Size() >= maxImplicitStackVarSize {
+ return "too large for stack"
+ }
+
+ if n.Op == OMAKESLICE {
+ r := n.Right
+ if r == nil {
+ r = n.Left
+ }
+ if !smallintconst(r) {
+ return "non-constant size"
+ }
+ if t := n.Type; t.Elem().Width != 0 && r.Int64Val() >= maxImplicitStackVarSize/t.Elem().Width {
+ return "too large for stack"
+ }
+ }
+
+ return ""
+}
+
+// addrescapes tags node n as having had its address taken
+// by "increasing" the "value" of n.Esc to EscHeap.
+// Storage is allocated as necessary to allow the address
+// to be taken.
+func addrescapes(n *Node) {
+ switch n.Op {
+ default:
+ // Unexpected Op, probably due to a previous type error. Ignore.
+
+ case ODEREF, ODOTPTR:
+ // Nothing to do.
+
+ case ONAME:
+ if n == nodfp {
+ break
+ }
+
+ // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
+ // on PPARAM it means something different.
+ if n.Class() == PAUTO && n.Esc == EscNever {
+ break
+ }
+
+ // If a closure reference escapes, mark the outer variable as escaping.
+ if n.Name.IsClosureVar() {
+ addrescapes(n.Name.Defn)
+ break
+ }
+
+ if n.Class() != PPARAM && n.Class() != PPARAMOUT && n.Class() != PAUTO {
+ break
+ }
+
+ // This is a plain parameter or local variable that needs to move to the heap,
+ // but possibly for the function outside the one we're compiling.
+ // That is, if we have:
+ //
+ // func f(x int) {
+ // func() {
+ // global = &x
+ // }
+ // }
+ //
+ // then we're analyzing the inner closure but we need to move x to the
+ // heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
+ oldfn := Curfn
+ Curfn = n.Name.Curfn
+ if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
+ Curfn = Curfn.Func.Closure
+ }
+ ln := lineno
+ lineno = Curfn.Pos
+ moveToHeap(n)
+ Curfn = oldfn
+ lineno = ln
+
+ // ODOTPTR has already been introduced,
+ // so these are the non-pointer ODOT and OINDEX.
+ // In &x[0], if x is a slice, then x does not
+ // escape--the pointer inside x does, but that
+ // is always a heap pointer anyway.
+ case ODOT, OINDEX, OPAREN, OCONVNOP:
+ if !n.Left.Type.IsSlice() {
+ addrescapes(n.Left)
+ }
+ }
+}
+
+// moveToHeap records the parameter or local variable n as moved to the heap.
+func moveToHeap(n *Node) {
+ if Debug.r != 0 {
+ Dump("MOVE", n)
+ }
+ if compiling_runtime {
+ yyerror("%v escapes to heap, not allowed in runtime", n)
+ }
+ if n.Class() == PAUTOHEAP {
+ Dump("n", n)
+ Fatalf("double move to heap")
+ }
+
+ // Allocate a local stack variable to hold the pointer to the heap copy.
+ // temp will add it to the function declaration list automatically.
+ heapaddr := temp(types.NewPtr(n.Type))
+ heapaddr.Sym = lookup("&" + n.Sym.Name)
+ heapaddr.Orig.Sym = heapaddr.Sym
+ heapaddr.Pos = n.Pos
+
+ // Unset AutoTemp to persist the &foo variable name through SSA to
+ // liveness analysis.
+ // TODO(mdempsky/drchase): Cleaner solution?
+ heapaddr.Name.SetAutoTemp(false)
+
+ // Parameters have a local stack copy used at function start/end
+ // in addition to the copy in the heap that may live longer than
+ // the function.
+ if n.Class() == PPARAM || n.Class() == PPARAMOUT {
+ if n.Xoffset == BADWIDTH {
+ Fatalf("addrescapes before param assignment")
+ }
+
+ // We rewrite n below to be a heap variable (indirection of heapaddr).
+ // Preserve a copy so we can still write code referring to the original,
+ // and substitute that copy into the function declaration list
+ // so that analyses of the local (on-stack) variables use it.
+ stackcopy := newname(n.Sym)
+ stackcopy.Type = n.Type
+ stackcopy.Xoffset = n.Xoffset
+ stackcopy.SetClass(n.Class())
+ stackcopy.Name.Param.Heapaddr = heapaddr
+ if n.Class() == PPARAMOUT {
+ // Make sure the pointer to the heap copy is kept live throughout the function.
+ // The function could panic at any point, and then a defer could recover.
+ // Thus, we need the pointer to the heap copy always available so the
+ // post-deferreturn code can copy the return value back to the stack.
+ // See issue 16095.
+ heapaddr.Name.SetIsOutputParamHeapAddr(true)
+ }
+ n.Name.Param.Stackcopy = stackcopy
+
+ // Substitute the stackcopy into the function variable list so that
+ // liveness and other analyses use the underlying stack slot
+ // and not the now-pseudo-variable n.
+ found := false
+ for i, d := range Curfn.Func.Dcl {
+ if d == n {
+ Curfn.Func.Dcl[i] = stackcopy
+ found = true
+ break
+ }
+ // Parameters are before locals, so can stop early.
+ // This limits the search even in functions with many local variables.
+ if d.Class() == PAUTO {
+ break
+ }
+ }
+ if !found {
+ Fatalf("cannot find %v in local variable list", n)
+ }
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+ }
+
+ // Modify n in place so that uses of n now mean indirection of the heapaddr.
+ n.SetClass(PAUTOHEAP)
+ n.Xoffset = 0
+ n.Name.Param.Heapaddr = heapaddr
+ n.Esc = EscHeap
+ if Debug.m != 0 {
+ Warnl(n.Pos, "moved to heap: %v", n)
+ }
+}
+
+// This special tag is applied to uintptr variables
+// that we believe may hold unsafe.Pointers for
+// calls into assembly functions.
+const unsafeUintptrTag = "unsafe-uintptr"
+
+// This special tag is applied to uintptr parameters of functions
+// marked go:uintptrescapes.
+const uintptrEscapesTag = "uintptr-escapes"
+
+func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
+ name := func() string {
+ if f.Sym != nil {
+ return f.Sym.Name
+ }
+ return fmt.Sprintf("arg#%d", narg)
+ }
+
+ if fn.Nbody.Len() == 0 {
+ // Assume that uintptr arguments must be held live across the call.
+ // This is most important for syscall.Syscall.
+ // See golang.org/issue/13372.
+ // This really doesn't have much to do with escape analysis per se,
+ // but we are reusing the ability to annotate an individual function
+ // argument and pass those annotations along to importing code.
+ if f.Type.IsUintptr() {
+ if Debug.m != 0 {
+ Warnl(f.Pos, "assuming %v is unsafe uintptr", name())
+ }
+ return unsafeUintptrTag
+ }
+
+ if !f.Type.HasPointers() { // don't bother tagging for scalars
+ return ""
+ }
+
+ var esc EscLeaks
+
+ // External functions are assumed unsafe, unless
+ // //go:noescape is given before the declaration.
+ if fn.Func.Pragma&Noescape != 0 {
+ if Debug.m != 0 && f.Sym != nil {
+ Warnl(f.Pos, "%v does not escape", name())
+ }
+ } else {
+ if Debug.m != 0 && f.Sym != nil {
+ Warnl(f.Pos, "leaking param: %v", name())
+ }
+ esc.AddHeap(0)
+ }
+
+ return esc.Encode()
+ }
+
+ if fn.Func.Pragma&UintptrEscapes != 0 {
+ if f.Type.IsUintptr() {
+ if Debug.m != 0 {
+ Warnl(f.Pos, "marking %v as escaping uintptr", name())
+ }
+ return uintptrEscapesTag
+ }
+ if f.IsDDD() && f.Type.Elem().IsUintptr() {
+ // final argument is ...uintptr.
+ if Debug.m != 0 {
+ Warnl(f.Pos, "marking %v as escaping ...uintptr", name())
+ }
+ return uintptrEscapesTag
+ }
+ }
+
+ if !f.Type.HasPointers() { // don't bother tagging for scalars
+ return ""
+ }
+
+ // Unnamed parameters are unused and therefore do not escape.
+ if f.Sym == nil || f.Sym.IsBlank() {
+ var esc EscLeaks
+ return esc.Encode()
+ }
+
+ n := asNode(f.Nname)
+ loc := e.oldLoc(n)
+ esc := loc.paramEsc
+ esc.Optimize()
+
+ if Debug.m != 0 && !loc.escapes {
+ if esc.Empty() {
+ Warnl(f.Pos, "%v does not escape", name())
+ }
+ if x := esc.Heap(); x >= 0 {
+ if x == 0 {
+ Warnl(f.Pos, "leaking param: %v", name())
+ } else {
+ // TODO(mdempsky): Mention level=x like below?
+ Warnl(f.Pos, "leaking param content: %v", name())
+ }
+ }
+ for i := 0; i < numEscResults; i++ {
+ if x := esc.Result(i); x >= 0 {
+ res := fn.Type.Results().Field(i).Sym
+ Warnl(f.Pos, "leaking param: %v to result %v level=%d", name(), res, x)
+ }
+ }
+ }
+
+ return esc.Encode()
+}
diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go
new file mode 100644
index 0000000..f719892
--- /dev/null
+++ b/src/cmd/compile/internal/gc/escape.go
@@ -0,0 +1,1539 @@
+// Copyright 2018 The Go Authors. 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/logopt"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "fmt"
+ "math"
+ "strings"
+)
+
+// Escape analysis.
+//
+// Here we analyze functions to determine which Go variables
+// (including implicit allocations such as calls to "new" or "make",
+// composite literals, etc.) can be allocated on the stack. The two
+// key invariants we have to ensure are: (1) pointers to stack objects
+// cannot be stored in the heap, and (2) pointers to a stack object
+// cannot outlive that object (e.g., because the declaring function
+// returned and destroyed the object's stack frame, or its space is
+// reused across loop iterations for logically distinct variables).
+//
+// We implement this with a static data-flow analysis of the AST.
+// First, we construct a directed weighted graph where vertices
+// (termed "locations") represent variables allocated by statements
+// and expressions, and edges represent assignments between variables
+// (with weights representing addressing/dereference counts).
+//
+// Next we walk the graph looking for assignment paths that might
+// violate the invariants stated above. If a variable v's address is
+// stored in the heap or elsewhere that may outlive it, then v is
+// marked as requiring heap allocation.
+//
+// To support interprocedural analysis, we also record data-flow from
+// each function's parameters to the heap and to its result
+// parameters. This information is summarized as "parameter tags",
+// which are used at static call sites to improve escape analysis of
+// function arguments.
+
+// Constructing the location graph.
+//
+// Every allocating statement (e.g., variable declaration) or
+// expression (e.g., "new" or "make") is first mapped to a unique
+// "location."
+//
+// We also model every Go assignment as a directed edges between
+// locations. The number of dereference operations minus the number of
+// addressing operations is recorded as the edge's weight (termed
+// "derefs"). For example:
+//
+// p = &q // -1
+// p = q // 0
+// p = *q // 1
+// p = **q // 2
+//
+// p = **&**&q // 2
+//
+// Note that the & operator can only be applied to addressable
+// expressions, and the expression &x itself is not addressable, so
+// derefs cannot go below -1.
+//
+// Every Go language construct is lowered into this representation,
+// generally without sensitivity to flow, path, or context; and
+// without distinguishing elements within a compound variable. For
+// example:
+//
+// var x struct { f, g *int }
+// var u []*int
+//
+// x.f = u[0]
+//
+// is modeled simply as
+//
+// x = *u
+//
+// That is, we don't distinguish x.f from x.g, or u[0] from u[1],
+// u[2], etc. However, we do record the implicit dereference involved
+// in indexing a slice.
+
+type Escape struct {
+ allLocs []*EscLocation
+
+ curfn *Node
+
+ // loopDepth counts the current loop nesting depth within
+ // curfn. It increments within each "for" loop and at each
+ // label with a corresponding backwards "goto" (i.e.,
+ // unstructured loop).
+ loopDepth int
+
+ heapLoc EscLocation
+ blankLoc EscLocation
+}
+
+// An EscLocation represents an abstract location that stores a Go
+// variable.
+type EscLocation struct {
+ n *Node // represented variable or expression, if any
+ curfn *Node // enclosing function
+ edges []EscEdge // incoming edges
+ loopDepth int // loopDepth at declaration
+
+ // derefs and walkgen are used during walkOne to track the
+ // minimal dereferences from the walk root.
+ derefs int // >= -1
+ walkgen uint32
+
+ // dst and dstEdgeindex track the next immediate assignment
+ // destination location during walkone, along with the index
+ // of the edge pointing back to this location.
+ dst *EscLocation
+ dstEdgeIdx int
+
+ // queued is used by walkAll to track whether this location is
+ // in the walk queue.
+ queued bool
+
+ // escapes reports whether the represented variable's address
+ // escapes; that is, whether the variable must be heap
+ // allocated.
+ escapes bool
+
+ // transient reports whether the represented expression's
+ // address does not outlive the statement; that is, whether
+ // its storage can be immediately reused.
+ transient bool
+
+ // paramEsc records the represented parameter's leak set.
+ paramEsc EscLeaks
+}
+
+// An EscEdge represents an assignment edge between two Go variables.
+type EscEdge struct {
+ src *EscLocation
+ derefs int // >= -1
+ notes *EscNote
+}
+
+// escapeFuncs performs escape analysis on a minimal batch of
+// functions.
+func escapeFuncs(fns []*Node, recursive bool) {
+ for _, fn := range fns {
+ if fn.Op != ODCLFUNC {
+ Fatalf("unexpected node: %v", fn)
+ }
+ }
+
+ var e Escape
+ e.heapLoc.escapes = true
+
+ // Construct data-flow graph from syntax trees.
+ for _, fn := range fns {
+ e.initFunc(fn)
+ }
+ for _, fn := range fns {
+ e.walkFunc(fn)
+ }
+ e.curfn = nil
+
+ e.walkAll()
+ e.finish(fns)
+}
+
+func (e *Escape) initFunc(fn *Node) {
+ if fn.Op != ODCLFUNC || fn.Esc != EscFuncUnknown {
+ Fatalf("unexpected node: %v", fn)
+ }
+ fn.Esc = EscFuncPlanned
+ if Debug.m > 3 {
+ Dump("escAnalyze", fn)
+ }
+
+ e.curfn = fn
+ e.loopDepth = 1
+
+ // Allocate locations for local variables.
+ for _, dcl := range fn.Func.Dcl {
+ if dcl.Op == ONAME {
+ e.newLoc(dcl, false)
+ }
+ }
+}
+
+func (e *Escape) walkFunc(fn *Node) {
+ fn.Esc = EscFuncStarted
+
+ // Identify labels that mark the head of an unstructured loop.
+ inspectList(fn.Nbody, func(n *Node) bool {
+ switch n.Op {
+ case OLABEL:
+ n.Sym.Label = asTypesNode(&nonlooping)
+
+ case OGOTO:
+ // If we visited the label before the goto,
+ // then this is a looping label.
+ if n.Sym.Label == asTypesNode(&nonlooping) {
+ n.Sym.Label = asTypesNode(&looping)
+ }
+ }
+
+ return true
+ })
+
+ e.curfn = fn
+ e.loopDepth = 1
+ e.block(fn.Nbody)
+}
+
+// Below we implement the methods for walking the AST and recording
+// data flow edges. Note that because a sub-expression might have
+// side-effects, it's important to always visit the entire AST.
+//
+// For example, write either:
+//
+// if x {
+// e.discard(n.Left)
+// } else {
+// e.value(k, n.Left)
+// }
+//
+// or
+//
+// if x {
+// k = e.discardHole()
+// }
+// e.value(k, n.Left)
+//
+// Do NOT write:
+//
+// // BAD: possibly loses side-effects within n.Left
+// if !x {
+// e.value(k, n.Left)
+// }
+
+// stmt evaluates a single Go statement.
+func (e *Escape) stmt(n *Node) {
+ if n == nil {
+ return
+ }
+
+ lno := setlineno(n)
+ defer func() {
+ lineno = lno
+ }()
+
+ if Debug.m > 2 {
+ fmt.Printf("%v:[%d] %v stmt: %v\n", linestr(lineno), e.loopDepth, funcSym(e.curfn), n)
+ }
+
+ e.stmts(n.Ninit)
+
+ switch n.Op {
+ default:
+ Fatalf("unexpected stmt: %v", n)
+
+ case ODCLCONST, ODCLTYPE, OEMPTY, OFALL, OINLMARK:
+ // nop
+
+ case OBREAK, OCONTINUE, OGOTO:
+ // TODO(mdempsky): Handle dead code?
+
+ case OBLOCK:
+ e.stmts(n.List)
+
+ case ODCL:
+ // Record loop depth at declaration.
+ if !n.Left.isBlank() {
+ e.dcl(n.Left)
+ }
+
+ case OLABEL:
+ switch asNode(n.Sym.Label) {
+ case &nonlooping:
+ if Debug.m > 2 {
+ fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n)
+ }
+ case &looping:
+ if Debug.m > 2 {
+ fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
+ }
+ e.loopDepth++
+ default:
+ Fatalf("label missing tag")
+ }
+ n.Sym.Label = nil
+
+ case OIF:
+ e.discard(n.Left)
+ e.block(n.Nbody)
+ e.block(n.Rlist)
+
+ case OFOR, OFORUNTIL:
+ e.loopDepth++
+ e.discard(n.Left)
+ e.stmt(n.Right)
+ e.block(n.Nbody)
+ e.loopDepth--
+
+ case ORANGE:
+ // for List = range Right { Nbody }
+ e.loopDepth++
+ ks := e.addrs(n.List)
+ e.block(n.Nbody)
+ e.loopDepth--
+
+ // Right is evaluated outside the loop.
+ k := e.discardHole()
+ if len(ks) >= 2 {
+ if n.Right.Type.IsArray() {
+ k = ks[1].note(n, "range")
+ } else {
+ k = ks[1].deref(n, "range-deref")
+ }
+ }
+ e.expr(e.later(k), n.Right)
+
+ case OSWITCH:
+ typesw := n.Left != nil && n.Left.Op == OTYPESW
+
+ var ks []EscHole
+ for _, cas := range n.List.Slice() { // cases
+ if typesw && n.Left.Left != nil {
+ cv := cas.Rlist.First()
+ k := e.dcl(cv) // type switch variables have no ODCL.
+ if cv.Type.HasPointers() {
+ ks = append(ks, k.dotType(cv.Type, cas, "switch case"))
+ }
+ }
+
+ e.discards(cas.List)
+ e.block(cas.Nbody)
+ }
+
+ if typesw {
+ e.expr(e.teeHole(ks...), n.Left.Right)
+ } else {
+ e.discard(n.Left)
+ }
+
+ case OSELECT:
+ for _, cas := range n.List.Slice() {
+ e.stmt(cas.Left)
+ e.block(cas.Nbody)
+ }
+ case OSELRECV:
+ e.assign(n.Left, n.Right, "selrecv", n)
+ case OSELRECV2:
+ e.assign(n.Left, n.Right, "selrecv", n)
+ e.assign(n.List.First(), nil, "selrecv", n)
+ case ORECV:
+ // TODO(mdempsky): Consider e.discard(n.Left).
+ e.exprSkipInit(e.discardHole(), n) // already visited n.Ninit
+ case OSEND:
+ e.discard(n.Left)
+ e.assignHeap(n.Right, "send", n)
+
+ case OAS, OASOP:
+ e.assign(n.Left, n.Right, "assign", n)
+
+ case OAS2:
+ for i, nl := range n.List.Slice() {
+ e.assign(nl, n.Rlist.Index(i), "assign-pair", n)
+ }
+
+ case OAS2DOTTYPE: // v, ok = x.(type)
+ e.assign(n.List.First(), n.Right, "assign-pair-dot-type", n)
+ e.assign(n.List.Second(), nil, "assign-pair-dot-type", n)
+ case OAS2MAPR: // v, ok = m[k]
+ e.assign(n.List.First(), n.Right, "assign-pair-mapr", n)
+ e.assign(n.List.Second(), nil, "assign-pair-mapr", n)
+ case OAS2RECV: // v, ok = <-ch
+ e.assign(n.List.First(), n.Right, "assign-pair-receive", n)
+ e.assign(n.List.Second(), nil, "assign-pair-receive", n)
+
+ case OAS2FUNC:
+ e.stmts(n.Right.Ninit)
+ e.call(e.addrs(n.List), n.Right, nil)
+ case ORETURN:
+ results := e.curfn.Type.Results().FieldSlice()
+ for i, v := range n.List.Slice() {
+ e.assign(asNode(results[i].Nname), v, "return", n)
+ }
+ case OCALLFUNC, OCALLMETH, OCALLINTER, OCLOSE, OCOPY, ODELETE, OPANIC, OPRINT, OPRINTN, ORECOVER:
+ e.call(nil, n, nil)
+ case OGO, ODEFER:
+ e.stmts(n.Left.Ninit)
+ e.call(nil, n.Left, n)
+
+ case ORETJMP:
+ // TODO(mdempsky): What do? esc.go just ignores it.
+ }
+}
+
+func (e *Escape) stmts(l Nodes) {
+ for _, n := range l.Slice() {
+ e.stmt(n)
+ }
+}
+
+// block is like stmts, but preserves loopDepth.
+func (e *Escape) block(l Nodes) {
+ old := e.loopDepth
+ e.stmts(l)
+ e.loopDepth = old
+}
+
+// expr models evaluating an expression n and flowing the result into
+// hole k.
+func (e *Escape) expr(k EscHole, n *Node) {
+ if n == nil {
+ return
+ }
+ e.stmts(n.Ninit)
+ e.exprSkipInit(k, n)
+}
+
+func (e *Escape) exprSkipInit(k EscHole, n *Node) {
+ if n == nil {
+ return
+ }
+
+ lno := setlineno(n)
+ defer func() {
+ lineno = lno
+ }()
+
+ uintptrEscapesHack := k.uintptrEscapesHack
+ k.uintptrEscapesHack = false
+
+ if uintptrEscapesHack && n.Op == OCONVNOP && n.Left.Type.IsUnsafePtr() {
+ // nop
+ } else if k.derefs >= 0 && !n.Type.HasPointers() {
+ k = e.discardHole()
+ }
+
+ switch n.Op {
+ default:
+ Fatalf("unexpected expr: %v", n)
+
+ case OLITERAL, OGETG, OCLOSUREVAR, OTYPE:
+ // nop
+
+ case ONAME:
+ if n.Class() == PFUNC || n.Class() == PEXTERN {
+ return
+ }
+ e.flow(k, e.oldLoc(n))
+
+ case OPLUS, ONEG, OBITNOT, ONOT:
+ e.discard(n.Left)
+ case OADD, OSUB, OOR, OXOR, OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT, OEQ, ONE, OLT, OLE, OGT, OGE, OANDAND, OOROR:
+ e.discard(n.Left)
+ e.discard(n.Right)
+
+ case OADDR:
+ e.expr(k.addr(n, "address-of"), n.Left) // "address-of"
+ case ODEREF:
+ e.expr(k.deref(n, "indirection"), n.Left) // "indirection"
+ case ODOT, ODOTMETH, ODOTINTER:
+ e.expr(k.note(n, "dot"), n.Left)
+ case ODOTPTR:
+ e.expr(k.deref(n, "dot of pointer"), n.Left) // "dot of pointer"
+ case ODOTTYPE, ODOTTYPE2:
+ e.expr(k.dotType(n.Type, n, "dot"), n.Left)
+ case OINDEX:
+ if n.Left.Type.IsArray() {
+ e.expr(k.note(n, "fixed-array-index-of"), n.Left)
+ } else {
+ // TODO(mdempsky): Fix why reason text.
+ e.expr(k.deref(n, "dot of pointer"), n.Left)
+ }
+ e.discard(n.Right)
+ case OINDEXMAP:
+ e.discard(n.Left)
+ e.discard(n.Right)
+ case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
+ e.expr(k.note(n, "slice"), n.Left)
+ low, high, max := n.SliceBounds()
+ e.discard(low)
+ e.discard(high)
+ e.discard(max)
+
+ case OCONV, OCONVNOP:
+ if checkPtr(e.curfn, 2) && n.Type.IsUnsafePtr() && n.Left.Type.IsPtr() {
+ // When -d=checkptr=2 is enabled, treat
+ // conversions to unsafe.Pointer as an
+ // escaping operation. This allows better
+ // runtime instrumentation, since we can more
+ // easily detect object boundaries on the heap
+ // than the stack.
+ e.assignHeap(n.Left, "conversion to unsafe.Pointer", n)
+ } else if n.Type.IsUnsafePtr() && n.Left.Type.IsUintptr() {
+ e.unsafeValue(k, n.Left)
+ } else {
+ e.expr(k, n.Left)
+ }
+ case OCONVIFACE:
+ if !n.Left.Type.IsInterface() && !isdirectiface(n.Left.Type) {
+ k = e.spill(k, n)
+ }
+ e.expr(k.note(n, "interface-converted"), n.Left)
+
+ case ORECV:
+ e.discard(n.Left)
+
+ case OCALLMETH, OCALLFUNC, OCALLINTER, OLEN, OCAP, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCOPY:
+ e.call([]EscHole{k}, n, nil)
+
+ case ONEW:
+ e.spill(k, n)
+
+ case OMAKESLICE:
+ e.spill(k, n)
+ e.discard(n.Left)
+ e.discard(n.Right)
+ case OMAKECHAN:
+ e.discard(n.Left)
+ case OMAKEMAP:
+ e.spill(k, n)
+ e.discard(n.Left)
+
+ case ORECOVER:
+ // nop
+
+ case OCALLPART:
+ // Flow the receiver argument to both the closure and
+ // to the receiver parameter.
+
+ closureK := e.spill(k, n)
+
+ m := callpartMethod(n)
+
+ // We don't know how the method value will be called
+ // later, so conservatively assume the result
+ // parameters all flow to the heap.
+ //
+ // TODO(mdempsky): Change ks into a callback, so that
+ // we don't have to create this dummy slice?
+ var ks []EscHole
+ for i := m.Type.NumResults(); i > 0; i-- {
+ ks = append(ks, e.heapHole())
+ }
+ paramK := e.tagHole(ks, asNode(m.Type.Nname()), m.Type.Recv())
+
+ e.expr(e.teeHole(paramK, closureK), n.Left)
+
+ case OPTRLIT:
+ e.expr(e.spill(k, n), n.Left)
+
+ case OARRAYLIT:
+ for _, elt := range n.List.Slice() {
+ if elt.Op == OKEY {
+ elt = elt.Right
+ }
+ e.expr(k.note(n, "array literal element"), elt)
+ }
+
+ case OSLICELIT:
+ k = e.spill(k, n)
+ k.uintptrEscapesHack = uintptrEscapesHack // for ...uintptr parameters
+
+ for _, elt := range n.List.Slice() {
+ if elt.Op == OKEY {
+ elt = elt.Right
+ }
+ e.expr(k.note(n, "slice-literal-element"), elt)
+ }
+
+ case OSTRUCTLIT:
+ for _, elt := range n.List.Slice() {
+ e.expr(k.note(n, "struct literal element"), elt.Left)
+ }
+
+ case OMAPLIT:
+ e.spill(k, n)
+
+ // Map keys and values are always stored in the heap.
+ for _, elt := range n.List.Slice() {
+ e.assignHeap(elt.Left, "map literal key", n)
+ e.assignHeap(elt.Right, "map literal value", n)
+ }
+
+ case OCLOSURE:
+ k = e.spill(k, n)
+
+ // Link addresses of captured variables to closure.
+ for _, v := range n.Func.Closure.Func.Cvars.Slice() {
+ if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
+ continue
+ }
+
+ k := k
+ if !v.Name.Byval() {
+ k = k.addr(v, "reference")
+ }
+
+ e.expr(k.note(n, "captured by a closure"), v.Name.Defn)
+ }
+
+ case ORUNES2STR, OBYTES2STR, OSTR2RUNES, OSTR2BYTES, ORUNESTR:
+ e.spill(k, n)
+ e.discard(n.Left)
+
+ case OADDSTR:
+ e.spill(k, n)
+
+ // Arguments of OADDSTR never escape;
+ // runtime.concatstrings makes sure of that.
+ e.discards(n.List)
+ }
+}
+
+// unsafeValue evaluates a uintptr-typed arithmetic expression looking
+// for conversions from an unsafe.Pointer.
+func (e *Escape) unsafeValue(k EscHole, n *Node) {
+ if n.Type.Etype != TUINTPTR {
+ Fatalf("unexpected type %v for %v", n.Type, n)
+ }
+
+ e.stmts(n.Ninit)
+
+ switch n.Op {
+ case OCONV, OCONVNOP:
+ if n.Left.Type.IsUnsafePtr() {
+ e.expr(k, n.Left)
+ } else {
+ e.discard(n.Left)
+ }
+ case ODOTPTR:
+ if isReflectHeaderDataField(n) {
+ e.expr(k.deref(n, "reflect.Header.Data"), n.Left)
+ } else {
+ e.discard(n.Left)
+ }
+ case OPLUS, ONEG, OBITNOT:
+ e.unsafeValue(k, n.Left)
+ case OADD, OSUB, OOR, OXOR, OMUL, ODIV, OMOD, OAND, OANDNOT:
+ e.unsafeValue(k, n.Left)
+ e.unsafeValue(k, n.Right)
+ case OLSH, ORSH:
+ e.unsafeValue(k, n.Left)
+ // RHS need not be uintptr-typed (#32959) and can't meaningfully
+ // flow pointers anyway.
+ e.discard(n.Right)
+ default:
+ e.exprSkipInit(e.discardHole(), n)
+ }
+}
+
+// discard evaluates an expression n for side-effects, but discards
+// its value.
+func (e *Escape) discard(n *Node) {
+ e.expr(e.discardHole(), n)
+}
+
+func (e *Escape) discards(l Nodes) {
+ for _, n := range l.Slice() {
+ e.discard(n)
+ }
+}
+
+// addr evaluates an addressable expression n and returns an EscHole
+// that represents storing into the represented location.
+func (e *Escape) addr(n *Node) EscHole {
+ if n == nil || n.isBlank() {
+ // Can happen at least in OSELRECV.
+ // TODO(mdempsky): Anywhere else?
+ return e.discardHole()
+ }
+
+ k := e.heapHole()
+
+ switch n.Op {
+ default:
+ Fatalf("unexpected addr: %v", n)
+ case ONAME:
+ if n.Class() == PEXTERN {
+ break
+ }
+ k = e.oldLoc(n).asHole()
+ case ODOT:
+ k = e.addr(n.Left)
+ case OINDEX:
+ e.discard(n.Right)
+ if n.Left.Type.IsArray() {
+ k = e.addr(n.Left)
+ } else {
+ e.discard(n.Left)
+ }
+ case ODEREF, ODOTPTR:
+ e.discard(n)
+ case OINDEXMAP:
+ e.discard(n.Left)
+ e.assignHeap(n.Right, "key of map put", n)
+ }
+
+ if !n.Type.HasPointers() {
+ k = e.discardHole()
+ }
+
+ return k
+}
+
+func (e *Escape) addrs(l Nodes) []EscHole {
+ var ks []EscHole
+ for _, n := range l.Slice() {
+ ks = append(ks, e.addr(n))
+ }
+ return ks
+}
+
+// assign evaluates the assignment dst = src.
+func (e *Escape) assign(dst, src *Node, why string, where *Node) {
+ // Filter out some no-op assignments for escape analysis.
+ ignore := dst != nil && src != nil && isSelfAssign(dst, src)
+ if ignore && Debug.m != 0 {
+ Warnl(where.Pos, "%v ignoring self-assignment in %S", funcSym(e.curfn), where)
+ }
+
+ k := e.addr(dst)
+ if dst != nil && dst.Op == ODOTPTR && isReflectHeaderDataField(dst) {
+ e.unsafeValue(e.heapHole().note(where, why), src)
+ } else {
+ if ignore {
+ k = e.discardHole()
+ }
+ e.expr(k.note(where, why), src)
+ }
+}
+
+func (e *Escape) assignHeap(src *Node, why string, where *Node) {
+ e.expr(e.heapHole().note(where, why), src)
+}
+
+// call evaluates a call expressions, including builtin calls. ks
+// should contain the holes representing where the function callee's
+// results flows; where is the OGO/ODEFER context of the call, if any.
+func (e *Escape) call(ks []EscHole, call, where *Node) {
+ topLevelDefer := where != nil && where.Op == ODEFER && e.loopDepth == 1
+ if topLevelDefer {
+ // force stack allocation of defer record, unless
+ // open-coded defers are used (see ssa.go)
+ where.Esc = EscNever
+ }
+
+ argument := func(k EscHole, arg *Node) {
+ if topLevelDefer {
+ // Top level defers arguments don't escape to
+ // heap, but they do need to last until end of
+ // function.
+ k = e.later(k)
+ } else if where != nil {
+ k = e.heapHole()
+ }
+
+ e.expr(k.note(call, "call parameter"), arg)
+ }
+
+ switch call.Op {
+ default:
+ Fatalf("unexpected call op: %v", call.Op)
+
+ case OCALLFUNC, OCALLMETH, OCALLINTER:
+ fixVariadicCall(call)
+
+ // Pick out the function callee, if statically known.
+ var fn *Node
+ switch call.Op {
+ case OCALLFUNC:
+ switch v := staticValue(call.Left); {
+ case v.Op == ONAME && v.Class() == PFUNC:
+ fn = v
+ case v.Op == OCLOSURE:
+ fn = v.Func.Closure.Func.Nname
+ }
+ case OCALLMETH:
+ fn = asNode(call.Left.Type.FuncType().Nname)
+ }
+
+ fntype := call.Left.Type
+ if fn != nil {
+ fntype = fn.Type
+ }
+
+ if ks != nil && fn != nil && e.inMutualBatch(fn) {
+ for i, result := range fn.Type.Results().FieldSlice() {
+ e.expr(ks[i], asNode(result.Nname))
+ }
+ }
+
+ if r := fntype.Recv(); r != nil {
+ argument(e.tagHole(ks, fn, r), call.Left.Left)
+ } else {
+ // Evaluate callee function expression.
+ argument(e.discardHole(), call.Left)
+ }
+
+ args := call.List.Slice()
+ for i, param := range fntype.Params().FieldSlice() {
+ argument(e.tagHole(ks, fn, param), args[i])
+ }
+
+ case OAPPEND:
+ args := call.List.Slice()
+
+ // Appendee slice may flow directly to the result, if
+ // it has enough capacity. Alternatively, a new heap
+ // slice might be allocated, and all slice elements
+ // might flow to heap.
+ appendeeK := ks[0]
+ if args[0].Type.Elem().HasPointers() {
+ appendeeK = e.teeHole(appendeeK, e.heapHole().deref(call, "appendee slice"))
+ }
+ argument(appendeeK, args[0])
+
+ if call.IsDDD() {
+ appendedK := e.discardHole()
+ if args[1].Type.IsSlice() && args[1].Type.Elem().HasPointers() {
+ appendedK = e.heapHole().deref(call, "appended slice...")
+ }
+ argument(appendedK, args[1])
+ } else {
+ for _, arg := range args[1:] {
+ argument(e.heapHole(), arg)
+ }
+ }
+
+ case OCOPY:
+ argument(e.discardHole(), call.Left)
+
+ copiedK := e.discardHole()
+ if call.Right.Type.IsSlice() && call.Right.Type.Elem().HasPointers() {
+ copiedK = e.heapHole().deref(call, "copied slice")
+ }
+ argument(copiedK, call.Right)
+
+ case OPANIC:
+ argument(e.heapHole(), call.Left)
+
+ case OCOMPLEX:
+ argument(e.discardHole(), call.Left)
+ argument(e.discardHole(), call.Right)
+ case ODELETE, OPRINT, OPRINTN, ORECOVER:
+ for _, arg := range call.List.Slice() {
+ argument(e.discardHole(), arg)
+ }
+ case OLEN, OCAP, OREAL, OIMAG, OCLOSE:
+ argument(e.discardHole(), call.Left)
+ }
+}
+
+// tagHole returns a hole for evaluating an argument passed to param.
+// ks should contain the holes representing where the function
+// callee's results flows. fn is the statically-known callee function,
+// if any.
+func (e *Escape) tagHole(ks []EscHole, fn *Node, param *types.Field) EscHole {
+ // If this is a dynamic call, we can't rely on param.Note.
+ if fn == nil {
+ return e.heapHole()
+ }
+
+ if e.inMutualBatch(fn) {
+ return e.addr(asNode(param.Nname))
+ }
+
+ // Call to previously tagged function.
+
+ if param.Note == uintptrEscapesTag {
+ k := e.heapHole()
+ k.uintptrEscapesHack = true
+ return k
+ }
+
+ var tagKs []EscHole
+
+ esc := ParseLeaks(param.Note)
+ if x := esc.Heap(); x >= 0 {
+ tagKs = append(tagKs, e.heapHole().shift(x))
+ }
+
+ if ks != nil {
+ for i := 0; i < numEscResults; i++ {
+ if x := esc.Result(i); x >= 0 {
+ tagKs = append(tagKs, ks[i].shift(x))
+ }
+ }
+ }
+
+ return e.teeHole(tagKs...)
+}
+
+// inMutualBatch reports whether function fn is in the batch of
+// mutually recursive functions being analyzed. When this is true,
+// fn has not yet been analyzed, so its parameters and results
+// should be incorporated directly into the flow graph instead of
+// relying on its escape analysis tagging.
+func (e *Escape) inMutualBatch(fn *Node) bool {
+ if fn.Name.Defn != nil && fn.Name.Defn.Esc < EscFuncTagged {
+ if fn.Name.Defn.Esc == EscFuncUnknown {
+ Fatalf("graph inconsistency")
+ }
+ return true
+ }
+ return false
+}
+
+// An EscHole represents a context for evaluation a Go
+// expression. E.g., when evaluating p in "x = **p", we'd have a hole
+// with dst==x and derefs==2.
+type EscHole struct {
+ dst *EscLocation
+ derefs int // >= -1
+ notes *EscNote
+
+ // uintptrEscapesHack indicates this context is evaluating an
+ // argument for a //go:uintptrescapes function.
+ uintptrEscapesHack bool
+}
+
+type EscNote struct {
+ next *EscNote
+ where *Node
+ why string
+}
+
+func (k EscHole) note(where *Node, why string) EscHole {
+ if where == nil || why == "" {
+ Fatalf("note: missing where/why")
+ }
+ if Debug.m >= 2 || logopt.Enabled() {
+ k.notes = &EscNote{
+ next: k.notes,
+ where: where,
+ why: why,
+ }
+ }
+ return k
+}
+
+func (k EscHole) shift(delta int) EscHole {
+ k.derefs += delta
+ if k.derefs < -1 {
+ Fatalf("derefs underflow: %v", k.derefs)
+ }
+ return k
+}
+
+func (k EscHole) deref(where *Node, why string) EscHole { return k.shift(1).note(where, why) }
+func (k EscHole) addr(where *Node, why string) EscHole { return k.shift(-1).note(where, why) }
+
+func (k EscHole) dotType(t *types.Type, where *Node, why string) EscHole {
+ if !t.IsInterface() && !isdirectiface(t) {
+ k = k.shift(1)
+ }
+ return k.note(where, why)
+}
+
+// teeHole returns a new hole that flows into each hole of ks,
+// similar to the Unix tee(1) command.
+func (e *Escape) teeHole(ks ...EscHole) EscHole {
+ if len(ks) == 0 {
+ return e.discardHole()
+ }
+ if len(ks) == 1 {
+ return ks[0]
+ }
+ // TODO(mdempsky): Optimize if there's only one non-discard hole?
+
+ // Given holes "l1 = _", "l2 = **_", "l3 = *_", ..., create a
+ // new temporary location ltmp, wire it into place, and return
+ // a hole for "ltmp = _".
+ loc := e.newLoc(nil, true)
+ for _, k := range ks {
+ // N.B., "p = &q" and "p = &tmp; tmp = q" are not
+ // semantically equivalent. To combine holes like "l1
+ // = _" and "l2 = &_", we'd need to wire them as "l1 =
+ // *ltmp" and "l2 = ltmp" and return "ltmp = &_"
+ // instead.
+ if k.derefs < 0 {
+ Fatalf("teeHole: negative derefs")
+ }
+
+ e.flow(k, loc)
+ }
+ return loc.asHole()
+}
+
+func (e *Escape) dcl(n *Node) EscHole {
+ loc := e.oldLoc(n)
+ loc.loopDepth = e.loopDepth
+ return loc.asHole()
+}
+
+// spill allocates a new location associated with expression n, flows
+// its address to k, and returns a hole that flows values to it. It's
+// intended for use with most expressions that allocate storage.
+func (e *Escape) spill(k EscHole, n *Node) EscHole {
+ loc := e.newLoc(n, true)
+ e.flow(k.addr(n, "spill"), loc)
+ return loc.asHole()
+}
+
+// later returns a new hole that flows into k, but some time later.
+// Its main effect is to prevent immediate reuse of temporary
+// variables introduced during Order.
+func (e *Escape) later(k EscHole) EscHole {
+ loc := e.newLoc(nil, false)
+ e.flow(k, loc)
+ return loc.asHole()
+}
+
+// canonicalNode returns the canonical *Node that n logically
+// represents.
+func canonicalNode(n *Node) *Node {
+ if n != nil && n.Op == ONAME && n.Name.IsClosureVar() {
+ n = n.Name.Defn
+ if n.Name.IsClosureVar() {
+ Fatalf("still closure var")
+ }
+ }
+
+ return n
+}
+
+func (e *Escape) newLoc(n *Node, transient bool) *EscLocation {
+ if e.curfn == nil {
+ Fatalf("e.curfn isn't set")
+ }
+ if n != nil && n.Type != nil && n.Type.NotInHeap() {
+ yyerrorl(n.Pos, "%v is incomplete (or unallocatable); stack allocation disallowed", n.Type)
+ }
+
+ n = canonicalNode(n)
+ loc := &EscLocation{
+ n: n,
+ curfn: e.curfn,
+ loopDepth: e.loopDepth,
+ transient: transient,
+ }
+ e.allLocs = append(e.allLocs, loc)
+ if n != nil {
+ if n.Op == ONAME && n.Name.Curfn != e.curfn {
+ Fatalf("curfn mismatch: %v != %v", n.Name.Curfn, e.curfn)
+ }
+
+ if n.HasOpt() {
+ Fatalf("%v already has a location", n)
+ }
+ n.SetOpt(loc)
+
+ if why := heapAllocReason(n); why != "" {
+ e.flow(e.heapHole().addr(n, why), loc)
+ }
+ }
+ return loc
+}
+
+func (e *Escape) oldLoc(n *Node) *EscLocation {
+ n = canonicalNode(n)
+ return n.Opt().(*EscLocation)
+}
+
+func (l *EscLocation) asHole() EscHole {
+ return EscHole{dst: l}
+}
+
+func (e *Escape) flow(k EscHole, src *EscLocation) {
+ dst := k.dst
+ if dst == &e.blankLoc {
+ return
+ }
+ if dst == src && k.derefs >= 0 { // dst = dst, dst = *dst, ...
+ return
+ }
+ if dst.escapes && k.derefs < 0 { // dst = &src
+ if Debug.m >= 2 || logopt.Enabled() {
+ pos := linestr(src.n.Pos)
+ if Debug.m >= 2 {
+ fmt.Printf("%s: %v escapes to heap:\n", pos, src.n)
+ }
+ explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{})
+ if logopt.Enabled() {
+ logopt.LogOpt(src.n.Pos, "escapes", "escape", e.curfn.funcname(), fmt.Sprintf("%v escapes to heap", src.n), explanation)
+ }
+
+ }
+ src.escapes = true
+ return
+ }
+
+ // TODO(mdempsky): Deduplicate edges?
+ dst.edges = append(dst.edges, EscEdge{src: src, derefs: k.derefs, notes: k.notes})
+}
+
+func (e *Escape) heapHole() EscHole { return e.heapLoc.asHole() }
+func (e *Escape) discardHole() EscHole { return e.blankLoc.asHole() }
+
+// walkAll computes the minimal dereferences between all pairs of
+// locations.
+func (e *Escape) walkAll() {
+ // We use a work queue to keep track of locations that we need
+ // to visit, and repeatedly walk until we reach a fixed point.
+ //
+ // We walk once from each location (including the heap), and
+ // then re-enqueue each location on its transition from
+ // transient->!transient and !escapes->escapes, which can each
+ // happen at most once. So we take Θ(len(e.allLocs)) walks.
+
+ // LIFO queue, has enough room for e.allLocs and e.heapLoc.
+ todo := make([]*EscLocation, 0, len(e.allLocs)+1)
+ enqueue := func(loc *EscLocation) {
+ if !loc.queued {
+ todo = append(todo, loc)
+ loc.queued = true
+ }
+ }
+
+ for _, loc := range e.allLocs {
+ enqueue(loc)
+ }
+ enqueue(&e.heapLoc)
+
+ var walkgen uint32
+ for len(todo) > 0 {
+ root := todo[len(todo)-1]
+ todo = todo[:len(todo)-1]
+ root.queued = false
+
+ walkgen++
+ e.walkOne(root, walkgen, enqueue)
+ }
+}
+
+// walkOne computes the minimal number of dereferences from root to
+// all other locations.
+func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLocation)) {
+ // The data flow graph has negative edges (from addressing
+ // operations), so we use the Bellman-Ford algorithm. However,
+ // we don't have to worry about infinite negative cycles since
+ // we bound intermediate dereference counts to 0.
+
+ root.walkgen = walkgen
+ root.derefs = 0
+ root.dst = nil
+
+ todo := []*EscLocation{root} // LIFO queue
+ for len(todo) > 0 {
+ l := todo[len(todo)-1]
+ todo = todo[:len(todo)-1]
+
+ base := l.derefs
+
+ // If l.derefs < 0, then l's address flows to root.
+ addressOf := base < 0
+ if addressOf {
+ // For a flow path like "root = &l; l = x",
+ // l's address flows to root, but x's does
+ // not. We recognize this by lower bounding
+ // base at 0.
+ base = 0
+
+ // If l's address flows to a non-transient
+ // location, then l can't be transiently
+ // allocated.
+ if !root.transient && l.transient {
+ l.transient = false
+ enqueue(l)
+ }
+ }
+
+ if e.outlives(root, l) {
+ // l's value flows to root. If l is a function
+ // parameter and root is the heap or a
+ // corresponding result parameter, then record
+ // that value flow for tagging the function
+ // later.
+ if l.isName(PPARAM) {
+ if (logopt.Enabled() || Debug.m >= 2) && !l.escapes {
+ if Debug.m >= 2 {
+ fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", linestr(l.n.Pos), l.n, e.explainLoc(root), base)
+ }
+ explanation := e.explainPath(root, l)
+ if logopt.Enabled() {
+ logopt.LogOpt(l.n.Pos, "leak", "escape", e.curfn.funcname(),
+ fmt.Sprintf("parameter %v leaks to %s with derefs=%d", l.n, e.explainLoc(root), base), explanation)
+ }
+ }
+ l.leakTo(root, base)
+ }
+
+ // If l's address flows somewhere that
+ // outlives it, then l needs to be heap
+ // allocated.
+ if addressOf && !l.escapes {
+ if logopt.Enabled() || Debug.m >= 2 {
+ if Debug.m >= 2 {
+ fmt.Printf("%s: %v escapes to heap:\n", linestr(l.n.Pos), l.n)
+ }
+ explanation := e.explainPath(root, l)
+ if logopt.Enabled() {
+ logopt.LogOpt(l.n.Pos, "escape", "escape", e.curfn.funcname(), fmt.Sprintf("%v escapes to heap", l.n), explanation)
+ }
+ }
+ l.escapes = true
+ enqueue(l)
+ continue
+ }
+ }
+
+ for i, edge := range l.edges {
+ if edge.src.escapes {
+ continue
+ }
+ derefs := base + edge.derefs
+ if edge.src.walkgen != walkgen || edge.src.derefs > derefs {
+ edge.src.walkgen = walkgen
+ edge.src.derefs = derefs
+ edge.src.dst = l
+ edge.src.dstEdgeIdx = i
+ todo = append(todo, edge.src)
+ }
+ }
+ }
+}
+
+// explainPath prints an explanation of how src flows to the walk root.
+func (e *Escape) explainPath(root, src *EscLocation) []*logopt.LoggedOpt {
+ visited := make(map[*EscLocation]bool)
+ pos := linestr(src.n.Pos)
+ var explanation []*logopt.LoggedOpt
+ for {
+ // Prevent infinite loop.
+ if visited[src] {
+ if Debug.m >= 2 {
+ fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos)
+ }
+ break
+ }
+ visited[src] = true
+ dst := src.dst
+ edge := &dst.edges[src.dstEdgeIdx]
+ if edge.src != src {
+ Fatalf("path inconsistency: %v != %v", edge.src, src)
+ }
+
+ explanation = e.explainFlow(pos, dst, src, edge.derefs, edge.notes, explanation)
+
+ if dst == root {
+ break
+ }
+ src = dst
+ }
+
+ return explanation
+}
+
+func (e *Escape) explainFlow(pos string, dst, srcloc *EscLocation, derefs int, notes *EscNote, explanation []*logopt.LoggedOpt) []*logopt.LoggedOpt {
+ ops := "&"
+ if derefs >= 0 {
+ ops = strings.Repeat("*", derefs)
+ }
+ print := Debug.m >= 2
+
+ flow := fmt.Sprintf(" flow: %s = %s%v:", e.explainLoc(dst), ops, e.explainLoc(srcloc))
+ if print {
+ fmt.Printf("%s:%s\n", pos, flow)
+ }
+ if logopt.Enabled() {
+ var epos src.XPos
+ if notes != nil {
+ epos = notes.where.Pos
+ } else if srcloc != nil && srcloc.n != nil {
+ epos = srcloc.n.Pos
+ }
+ explanation = append(explanation, logopt.NewLoggedOpt(epos, "escflow", "escape", e.curfn.funcname(), flow))
+ }
+
+ for note := notes; note != nil; note = note.next {
+ if print {
+ fmt.Printf("%s: from %v (%v) at %s\n", pos, note.where, note.why, linestr(note.where.Pos))
+ }
+ if logopt.Enabled() {
+ explanation = append(explanation, logopt.NewLoggedOpt(note.where.Pos, "escflow", "escape", e.curfn.funcname(),
+ fmt.Sprintf(" from %v (%v)", note.where, note.why)))
+ }
+ }
+ return explanation
+}
+
+func (e *Escape) explainLoc(l *EscLocation) string {
+ if l == &e.heapLoc {
+ return "{heap}"
+ }
+ if l.n == nil {
+ // TODO(mdempsky): Omit entirely.
+ return "{temp}"
+ }
+ if l.n.Op == ONAME {
+ return fmt.Sprintf("%v", l.n)
+ }
+ return fmt.Sprintf("{storage for %v}", l.n)
+}
+
+// outlives reports whether values stored in l may survive beyond
+// other's lifetime if stack allocated.
+func (e *Escape) outlives(l, other *EscLocation) bool {
+ // The heap outlives everything.
+ if l.escapes {
+ return true
+ }
+
+ // We don't know what callers do with returned values, so
+ // pessimistically we need to assume they flow to the heap and
+ // outlive everything too.
+ if l.isName(PPARAMOUT) {
+ // Exception: Directly called closures can return
+ // locations allocated outside of them without forcing
+ // them to the heap. For example:
+ //
+ // var u int // okay to stack allocate
+ // *(func() *int { return &u }()) = 42
+ if containsClosure(other.curfn, l.curfn) && l.curfn.Func.Closure.Func.Top&ctxCallee != 0 {
+ return false
+ }
+
+ return true
+ }
+
+ // If l and other are within the same function, then l
+ // outlives other if it was declared outside other's loop
+ // scope. For example:
+ //
+ // var l *int
+ // for {
+ // l = new(int)
+ // }
+ if l.curfn == other.curfn && l.loopDepth < other.loopDepth {
+ return true
+ }
+
+ // If other is declared within a child closure of where l is
+ // declared, then l outlives it. For example:
+ //
+ // var l *int
+ // func() {
+ // l = new(int)
+ // }
+ if containsClosure(l.curfn, other.curfn) {
+ return true
+ }
+
+ return false
+}
+
+// containsClosure reports whether c is a closure contained within f.
+func containsClosure(f, c *Node) bool {
+ if f.Op != ODCLFUNC || c.Op != ODCLFUNC {
+ Fatalf("bad containsClosure: %v, %v", f, c)
+ }
+
+ // Common case.
+ if f == c {
+ return false
+ }
+
+ // Closures within function Foo are named like "Foo.funcN..."
+ // TODO(mdempsky): Better way to recognize this.
+ fn := f.Func.Nname.Sym.Name
+ cn := c.Func.Nname.Sym.Name
+ return len(cn) > len(fn) && cn[:len(fn)] == fn && cn[len(fn)] == '.'
+}
+
+// leak records that parameter l leaks to sink.
+func (l *EscLocation) leakTo(sink *EscLocation, derefs int) {
+ // If sink is a result parameter that doesn't escape (#44614)
+ // and we can fit return bits into the escape analysis tag,
+ // then record as a result leak.
+ if !sink.escapes && sink.isName(PPARAMOUT) && sink.curfn == l.curfn {
+ // TODO(mdempsky): Eliminate dependency on Vargen here.
+ ri := int(sink.n.Name.Vargen) - 1
+ if ri < numEscResults {
+ // Leak to result parameter.
+ l.paramEsc.AddResult(ri, derefs)
+ return
+ }
+ }
+
+ // Otherwise, record as heap leak.
+ l.paramEsc.AddHeap(derefs)
+}
+
+func (e *Escape) finish(fns []*Node) {
+ // Record parameter tags for package export data.
+ for _, fn := range fns {
+ fn.Esc = EscFuncTagged
+
+ narg := 0
+ for _, fs := range &types.RecvsParams {
+ for _, f := range fs(fn.Type).Fields().Slice() {
+ narg++
+ f.Note = e.paramTag(fn, narg, f)
+ }
+ }
+ }
+
+ for _, loc := range e.allLocs {
+ n := loc.n
+ if n == nil {
+ continue
+ }
+ n.SetOpt(nil)
+
+ // Update n.Esc based on escape analysis results.
+
+ if loc.escapes {
+ if n.Op != ONAME {
+ if Debug.m != 0 {
+ Warnl(n.Pos, "%S escapes to heap", n)
+ }
+ if logopt.Enabled() {
+ logopt.LogOpt(n.Pos, "escape", "escape", e.curfn.funcname())
+ }
+ }
+ n.Esc = EscHeap
+ addrescapes(n)
+ } else {
+ if Debug.m != 0 && n.Op != ONAME {
+ Warnl(n.Pos, "%S does not escape", n)
+ }
+ n.Esc = EscNone
+ if loc.transient {
+ n.SetTransient(true)
+ }
+ }
+ }
+}
+
+func (l *EscLocation) isName(c Class) bool {
+ return l.n != nil && l.n.Op == ONAME && l.n.Class() == c
+}
+
+const numEscResults = 7
+
+// An EscLeaks represents a set of assignment flows from a parameter
+// to the heap or to any of its function's (first numEscResults)
+// result parameters.
+type EscLeaks [1 + numEscResults]uint8
+
+// Empty reports whether l is an empty set (i.e., no assignment flows).
+func (l EscLeaks) Empty() bool { return l == EscLeaks{} }
+
+// Heap returns the minimum deref count of any assignment flow from l
+// to the heap. If no such flows exist, Heap returns -1.
+func (l EscLeaks) Heap() int { return l.get(0) }
+
+// Result returns the minimum deref count of any assignment flow from
+// l to its function's i'th result parameter. If no such flows exist,
+// Result returns -1.
+func (l EscLeaks) Result(i int) int { return l.get(1 + i) }
+
+// AddHeap adds an assignment flow from l to the heap.
+func (l *EscLeaks) AddHeap(derefs int) { l.add(0, derefs) }
+
+// AddResult adds an assignment flow from l to its function's i'th
+// result parameter.
+func (l *EscLeaks) AddResult(i, derefs int) { l.add(1+i, derefs) }
+
+func (l *EscLeaks) setResult(i, derefs int) { l.set(1+i, derefs) }
+
+func (l EscLeaks) get(i int) int { return int(l[i]) - 1 }
+
+func (l *EscLeaks) add(i, derefs int) {
+ if old := l.get(i); old < 0 || derefs < old {
+ l.set(i, derefs)
+ }
+}
+
+func (l *EscLeaks) set(i, derefs int) {
+ v := derefs + 1
+ if v < 0 {
+ Fatalf("invalid derefs count: %v", derefs)
+ }
+ if v > math.MaxUint8 {
+ v = math.MaxUint8
+ }
+
+ l[i] = uint8(v)
+}
+
+// Optimize removes result flow paths that are equal in length or
+// longer than the shortest heap flow path.
+func (l *EscLeaks) Optimize() {
+ // If we have a path to the heap, then there's no use in
+ // keeping equal or longer paths elsewhere.
+ if x := l.Heap(); x >= 0 {
+ for i := 0; i < numEscResults; i++ {
+ if l.Result(i) >= x {
+ l.setResult(i, -1)
+ }
+ }
+ }
+}
+
+var leakTagCache = map[EscLeaks]string{}
+
+// Encode converts l into a binary string for export data.
+func (l EscLeaks) Encode() string {
+ if l.Heap() == 0 {
+ // Space optimization: empty string encodes more
+ // efficiently in export data.
+ return ""
+ }
+ if s, ok := leakTagCache[l]; ok {
+ return s
+ }
+
+ n := len(l)
+ for n > 0 && l[n-1] == 0 {
+ n--
+ }
+ s := "esc:" + string(l[:n])
+ leakTagCache[l] = s
+ return s
+}
+
+// ParseLeaks parses a binary string representing an EscLeaks.
+func ParseLeaks(s string) EscLeaks {
+ var l EscLeaks
+ if !strings.HasPrefix(s, "esc:") {
+ l.AddHeap(0)
+ return l
+ }
+ copy(l[:], s[4:])
+ return l
+}
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
new file mode 100644
index 0000000..c6917e0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/export.go
@@ -0,0 +1,233 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/bio"
+ "cmd/internal/src"
+ "fmt"
+)
+
+var (
+ Debug_export int // if set, print debugging information about export data
+)
+
+func exportf(bout *bio.Writer, format string, args ...interface{}) {
+ fmt.Fprintf(bout, format, args...)
+ if Debug_export != 0 {
+ fmt.Printf(format, args...)
+ }
+}
+
+var asmlist []*Node
+
+// exportsym marks n for export (or reexport).
+func exportsym(n *Node) {
+ if n.Sym.OnExportList() {
+ return
+ }
+ n.Sym.SetOnExportList(true)
+
+ if Debug.E != 0 {
+ fmt.Printf("export symbol %v\n", n.Sym)
+ }
+
+ exportlist = append(exportlist, n)
+}
+
+func initname(s string) bool {
+ return s == "init"
+}
+
+func autoexport(n *Node, ctxt Class) {
+ if n.Sym.Pkg != localpkg {
+ return
+ }
+ if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
+ return
+ }
+ if n.Type != nil && n.Type.IsKind(TFUNC) && n.IsMethod() {
+ return
+ }
+
+ if types.IsExported(n.Sym.Name) || initname(n.Sym.Name) {
+ exportsym(n)
+ }
+ if asmhdr != "" && !n.Sym.Asm() {
+ n.Sym.SetAsm(true)
+ asmlist = append(asmlist, n)
+ }
+}
+
+func dumpexport(bout *bio.Writer) {
+ // The linker also looks for the $$ marker - use char after $$ to distinguish format.
+ exportf(bout, "\n$$B\n") // indicate binary export format
+ off := bout.Offset()
+ iexport(bout.Writer)
+ size := bout.Offset() - off
+ exportf(bout, "\n$$\n")
+
+ if Debug_export != 0 {
+ fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", myimportpath, size)
+ }
+}
+
+func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node {
+ n := asNode(s.PkgDef())
+ if n == nil {
+ // iimport should have created a stub ONONAME
+ // declaration for all imported symbols. The exception
+ // is declarations for Runtimepkg, which are populated
+ // by loadsys instead.
+ if s.Pkg != Runtimepkg {
+ Fatalf("missing ONONAME for %v\n", s)
+ }
+
+ n = dclname(s)
+ s.SetPkgDef(asTypesNode(n))
+ s.Importdef = ipkg
+ }
+ if n.Op != ONONAME && n.Op != op {
+ redeclare(lineno, s, fmt.Sprintf("during import %q", ipkg.Path))
+ }
+ return n
+}
+
+// importtype returns the named type declared by symbol s.
+// If no such type has been declared yet, a forward declaration is returned.
+// ipkg is the package being imported
+func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type {
+ n := importsym(ipkg, s, OTYPE)
+ if n.Op != OTYPE {
+ t := types.New(TFORW)
+ t.Sym = s
+ t.Nod = asTypesNode(n)
+
+ n.Op = OTYPE
+ n.Pos = pos
+ n.Type = t
+ n.SetClass(PEXTERN)
+ }
+
+ t := n.Type
+ if t == nil {
+ Fatalf("importtype %v", s)
+ }
+ return t
+}
+
+// importobj declares symbol s as an imported object representable by op.
+// ipkg is the package being imported
+func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op, ctxt Class, t *types.Type) *Node {
+ n := importsym(ipkg, s, op)
+ if n.Op != ONONAME {
+ if n.Op == op && (n.Class() != ctxt || !types.Identical(n.Type, t)) {
+ redeclare(lineno, s, fmt.Sprintf("during import %q", ipkg.Path))
+ }
+ return nil
+ }
+
+ n.Op = op
+ n.Pos = pos
+ n.SetClass(ctxt)
+ if ctxt == PFUNC {
+ n.Sym.SetFunc(true)
+ }
+ n.Type = t
+ return n
+}
+
+// importconst declares symbol s as an imported constant with type t and value val.
+// ipkg is the package being imported
+func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val Val) {
+ n := importobj(ipkg, pos, s, OLITERAL, PEXTERN, t)
+ if n == nil { // TODO: Check that value matches.
+ return
+ }
+
+ n.SetVal(val)
+
+ if Debug.E != 0 {
+ fmt.Printf("import const %v %L = %v\n", s, t, val)
+ }
+}
+
+// importfunc declares symbol s as an imported function with type t.
+// ipkg is the package being imported
+func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
+ n := importobj(ipkg, pos, s, ONAME, PFUNC, t)
+ if n == nil {
+ return
+ }
+
+ n.Func = new(Func)
+ t.SetNname(asTypesNode(n))
+
+ if Debug.E != 0 {
+ fmt.Printf("import func %v%S\n", s, t)
+ }
+}
+
+// importvar declares symbol s as an imported variable with type t.
+// ipkg is the package being imported
+func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
+ n := importobj(ipkg, pos, s, ONAME, PEXTERN, t)
+ if n == nil {
+ return
+ }
+
+ if Debug.E != 0 {
+ fmt.Printf("import var %v %L\n", s, t)
+ }
+}
+
+// importalias declares symbol s as an imported type alias with type t.
+// ipkg is the package being imported
+func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
+ n := importobj(ipkg, pos, s, OTYPE, PEXTERN, t)
+ if n == nil {
+ return
+ }
+
+ if Debug.E != 0 {
+ fmt.Printf("import type %v = %L\n", s, t)
+ }
+}
+
+func dumpasmhdr() {
+ b, err := bio.Create(asmhdr)
+ if err != nil {
+ Fatalf("%v", err)
+ }
+ fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
+ for _, n := range asmlist {
+ if n.Sym.IsBlank() {
+ continue
+ }
+ switch n.Op {
+ case OLITERAL:
+ t := n.Val().Ctype()
+ if t == CTFLT || t == CTCPLX {
+ break
+ }
+ fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
+
+ case OTYPE:
+ t := n.Type
+ if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
+ break
+ }
+ fmt.Fprintf(b, "#define %s__size %d\n", n.Sym.Name, int(t.Width))
+ for _, f := range t.Fields().Slice() {
+ if !f.Sym.IsBlank() {
+ fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, f.Sym.Name, int(f.Offset))
+ }
+ }
+ }
+ }
+
+ b.Close()
+}
diff --git a/src/cmd/compile/internal/gc/fixedbugs_test.go b/src/cmd/compile/internal/gc/fixedbugs_test.go
new file mode 100644
index 0000000..8ac4436
--- /dev/null
+++ b/src/cmd/compile/internal/gc/fixedbugs_test.go
@@ -0,0 +1,92 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+type T struct {
+ x [2]int64 // field that will be clobbered. Also makes type not SSAable.
+ p *byte // has a pointer
+}
+
+//go:noinline
+func makeT() T {
+ return T{}
+}
+
+var g T
+
+var sink interface{}
+
+func TestIssue15854(t *testing.T) {
+ for i := 0; i < 10000; i++ {
+ if g.x[0] != 0 {
+ t.Fatalf("g.x[0] clobbered with %x\n", g.x[0])
+ }
+ // The bug was in the following assignment. The return
+ // value of makeT() is not copied out of the args area of
+ // stack frame in a timely fashion. So when write barriers
+ // are enabled, the marshaling of the args for the write
+ // barrier call clobbers the result of makeT() before it is
+ // read by the write barrier code.
+ g = makeT()
+ sink = make([]byte, 1000) // force write barriers to eventually happen
+ }
+}
+func TestIssue15854b(t *testing.T) {
+ const N = 10000
+ a := make([]T, N)
+ for i := 0; i < N; i++ {
+ a = append(a, makeT())
+ sink = make([]byte, 1000) // force write barriers to eventually happen
+ }
+ for i, v := range a {
+ if v.x[0] != 0 {
+ t.Fatalf("a[%d].x[0] clobbered with %x\n", i, v.x[0])
+ }
+ }
+}
+
+// Test that the generated assembly has line numbers (Issue #16214).
+func TestIssue16214(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ dir, err := ioutil.TempDir("", "TestLineNumber")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ src := filepath.Join(dir, "x.go")
+ err = ioutil.WriteFile(src, []byte(issue16214src), 0644)
+ if err != nil {
+ t.Fatalf("could not write file: %v", err)
+ }
+
+ cmd := exec.Command(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)
+ }
+
+ if strings.Contains(string(out), "unknown line number") {
+ t.Errorf("line number missing in assembly:\n%s", out)
+ }
+}
+
+var issue16214src = `
+package main
+
+func Mod32(x uint32) uint32 {
+ return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos
+}
+`
diff --git a/src/cmd/compile/internal/gc/float_test.go b/src/cmd/compile/internal/gc/float_test.go
new file mode 100644
index 0000000..c619d25
--- /dev/null
+++ b/src/cmd/compile/internal/gc/float_test.go
@@ -0,0 +1,544 @@
+// Copyright 2016 The Go Authors. 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 (
+ "math"
+ "testing"
+)
+
+//go:noinline
+func compare1(a, b float64) bool {
+ return a < b
+}
+
+//go:noinline
+func compare2(a, b float32) bool {
+ return a < b
+}
+
+func TestFloatCompare(t *testing.T) {
+ if !compare1(3, 5) {
+ t.Errorf("compare1 returned false")
+ }
+ if !compare2(3, 5) {
+ t.Errorf("compare2 returned false")
+ }
+}
+
+func TestFloatCompareFolded(t *testing.T) {
+ // float64 comparisons
+ d1, d3, d5, d9 := float64(1), float64(3), float64(5), float64(9)
+ if d3 == d5 {
+ t.Errorf("d3 == d5 returned true")
+ }
+ if d3 != d3 {
+ t.Errorf("d3 != d3 returned true")
+ }
+ if d3 > d5 {
+ t.Errorf("d3 > d5 returned true")
+ }
+ if d3 >= d9 {
+ t.Errorf("d3 >= d9 returned true")
+ }
+ if d5 < d1 {
+ t.Errorf("d5 < d1 returned true")
+ }
+ if d9 <= d1 {
+ t.Errorf("d9 <= d1 returned true")
+ }
+ if math.NaN() == math.NaN() {
+ t.Errorf("math.NaN() == math.NaN() returned true")
+ }
+ if math.NaN() >= math.NaN() {
+ t.Errorf("math.NaN() >= math.NaN() returned true")
+ }
+ if math.NaN() <= math.NaN() {
+ t.Errorf("math.NaN() <= math.NaN() returned true")
+ }
+ if math.Copysign(math.NaN(), -1) < math.NaN() {
+ t.Errorf("math.Copysign(math.NaN(), -1) < math.NaN() returned true")
+ }
+ if math.Inf(1) != math.Inf(1) {
+ t.Errorf("math.Inf(1) != math.Inf(1) returned true")
+ }
+ if math.Inf(-1) != math.Inf(-1) {
+ t.Errorf("math.Inf(-1) != math.Inf(-1) returned true")
+ }
+ if math.Copysign(0, -1) != 0 {
+ t.Errorf("math.Copysign(0, -1) != 0 returned true")
+ }
+ if math.Copysign(0, -1) < 0 {
+ t.Errorf("math.Copysign(0, -1) < 0 returned true")
+ }
+ if 0 > math.Copysign(0, -1) {
+ t.Errorf("0 > math.Copysign(0, -1) returned true")
+ }
+
+ // float32 comparisons
+ s1, s3, s5, s9 := float32(1), float32(3), float32(5), float32(9)
+ if s3 == s5 {
+ t.Errorf("s3 == s5 returned true")
+ }
+ if s3 != s3 {
+ t.Errorf("s3 != s3 returned true")
+ }
+ if s3 > s5 {
+ t.Errorf("s3 > s5 returned true")
+ }
+ if s3 >= s9 {
+ t.Errorf("s3 >= s9 returned true")
+ }
+ if s5 < s1 {
+ t.Errorf("s5 < s1 returned true")
+ }
+ if s9 <= s1 {
+ t.Errorf("s9 <= s1 returned true")
+ }
+ sPosNaN, sNegNaN := float32(math.NaN()), float32(math.Copysign(math.NaN(), -1))
+ if sPosNaN == sPosNaN {
+ t.Errorf("sPosNaN == sPosNaN returned true")
+ }
+ if sPosNaN >= sPosNaN {
+ t.Errorf("sPosNaN >= sPosNaN returned true")
+ }
+ if sPosNaN <= sPosNaN {
+ t.Errorf("sPosNaN <= sPosNaN returned true")
+ }
+ if sNegNaN < sPosNaN {
+ t.Errorf("sNegNaN < sPosNaN returned true")
+ }
+ sPosInf, sNegInf := float32(math.Inf(1)), float32(math.Inf(-1))
+ if sPosInf != sPosInf {
+ t.Errorf("sPosInf != sPosInf returned true")
+ }
+ if sNegInf != sNegInf {
+ t.Errorf("sNegInf != sNegInf returned true")
+ }
+ sNegZero := float32(math.Copysign(0, -1))
+ if sNegZero != 0 {
+ t.Errorf("sNegZero != 0 returned true")
+ }
+ if sNegZero < 0 {
+ t.Errorf("sNegZero < 0 returned true")
+ }
+ if 0 > sNegZero {
+ t.Errorf("0 > sNegZero returned true")
+ }
+}
+
+//go:noinline
+func cvt1(a float64) uint64 {
+ return uint64(a)
+}
+
+//go:noinline
+func cvt2(a float64) uint32 {
+ return uint32(a)
+}
+
+//go:noinline
+func cvt3(a float32) uint64 {
+ return uint64(a)
+}
+
+//go:noinline
+func cvt4(a float32) uint32 {
+ return uint32(a)
+}
+
+//go:noinline
+func cvt5(a float64) int64 {
+ return int64(a)
+}
+
+//go:noinline
+func cvt6(a float64) int32 {
+ return int32(a)
+}
+
+//go:noinline
+func cvt7(a float32) int64 {
+ return int64(a)
+}
+
+//go:noinline
+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)
+}
+
+//go:noinline
+func f2i64p(v float64) *int64 {
+ return ip64(int64(v / 0.1))
+}
+
+//go:noinline
+func ip64(v int64) *int64 {
+ return &v
+}
+
+func TestFloatConvert(t *testing.T) {
+ if got := cvt1(3.5); got != 3 {
+ t.Errorf("cvt1 got %d, wanted 3", got)
+ }
+ if got := cvt2(3.5); got != 3 {
+ t.Errorf("cvt2 got %d, wanted 3", got)
+ }
+ if got := cvt3(3.5); got != 3 {
+ t.Errorf("cvt3 got %d, wanted 3", got)
+ }
+ if got := cvt4(3.5); got != 3 {
+ t.Errorf("cvt4 got %d, wanted 3", got)
+ }
+ if got := cvt5(3.5); got != 3 {
+ t.Errorf("cvt5 got %d, wanted 3", got)
+ }
+ if got := cvt6(3.5); got != 3 {
+ t.Errorf("cvt6 got %d, wanted 3", got)
+ }
+ if got := cvt7(3.5); got != 3 {
+ t.Errorf("cvt7 got %d, wanted 3", got)
+ }
+ 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)
+ }
+ if got := *f2i64p(10); got != 100 {
+ t.Errorf("f2i64p got %d, wanted 100", got)
+ }
+}
+
+func TestFloatConvertFolded(t *testing.T) {
+ // Assign constants to variables so that they are (hopefully) constant folded
+ // by the SSA backend rather than the frontend.
+ u64, u32, u16, u8 := uint64(1<<63), uint32(1<<31), uint16(1<<15), uint8(1<<7)
+ i64, i32, i16, i8 := int64(-1<<63), int32(-1<<31), int16(-1<<15), int8(-1<<7)
+ du64, du32, du16, du8 := float64(1<<63), float64(1<<31), float64(1<<15), float64(1<<7)
+ di64, di32, di16, di8 := float64(-1<<63), float64(-1<<31), float64(-1<<15), float64(-1<<7)
+ su64, su32, su16, su8 := float32(1<<63), float32(1<<31), float32(1<<15), float32(1<<7)
+ si64, si32, si16, si8 := float32(-1<<63), float32(-1<<31), float32(-1<<15), float32(-1<<7)
+
+ // integer to float
+ if float64(u64) != du64 {
+ t.Errorf("float64(u64) != du64")
+ }
+ if float64(u32) != du32 {
+ t.Errorf("float64(u32) != du32")
+ }
+ if float64(u16) != du16 {
+ t.Errorf("float64(u16) != du16")
+ }
+ if float64(u8) != du8 {
+ t.Errorf("float64(u8) != du8")
+ }
+ if float64(i64) != di64 {
+ t.Errorf("float64(i64) != di64")
+ }
+ if float64(i32) != di32 {
+ t.Errorf("float64(i32) != di32")
+ }
+ if float64(i16) != di16 {
+ t.Errorf("float64(i16) != di16")
+ }
+ if float64(i8) != di8 {
+ t.Errorf("float64(i8) != di8")
+ }
+ if float32(u64) != su64 {
+ t.Errorf("float32(u64) != su64")
+ }
+ if float32(u32) != su32 {
+ t.Errorf("float32(u32) != su32")
+ }
+ if float32(u16) != su16 {
+ t.Errorf("float32(u16) != su16")
+ }
+ if float32(u8) != su8 {
+ t.Errorf("float32(u8) != su8")
+ }
+ if float32(i64) != si64 {
+ t.Errorf("float32(i64) != si64")
+ }
+ if float32(i32) != si32 {
+ t.Errorf("float32(i32) != si32")
+ }
+ if float32(i16) != si16 {
+ t.Errorf("float32(i16) != si16")
+ }
+ if float32(i8) != si8 {
+ t.Errorf("float32(i8) != si8")
+ }
+
+ // float to integer
+ if uint64(du64) != u64 {
+ t.Errorf("uint64(du64) != u64")
+ }
+ if uint32(du32) != u32 {
+ t.Errorf("uint32(du32) != u32")
+ }
+ if uint16(du16) != u16 {
+ t.Errorf("uint16(du16) != u16")
+ }
+ if uint8(du8) != u8 {
+ t.Errorf("uint8(du8) != u8")
+ }
+ if int64(di64) != i64 {
+ t.Errorf("int64(di64) != i64")
+ }
+ if int32(di32) != i32 {
+ t.Errorf("int32(di32) != i32")
+ }
+ if int16(di16) != i16 {
+ t.Errorf("int16(di16) != i16")
+ }
+ if int8(di8) != i8 {
+ t.Errorf("int8(di8) != i8")
+ }
+ if uint64(su64) != u64 {
+ t.Errorf("uint64(su64) != u64")
+ }
+ if uint32(su32) != u32 {
+ t.Errorf("uint32(su32) != u32")
+ }
+ if uint16(su16) != u16 {
+ t.Errorf("uint16(su16) != u16")
+ }
+ if uint8(su8) != u8 {
+ t.Errorf("uint8(su8) != u8")
+ }
+ if int64(si64) != i64 {
+ t.Errorf("int64(si64) != i64")
+ }
+ if int32(si32) != i32 {
+ t.Errorf("int32(si32) != i32")
+ }
+ if int16(si16) != i16 {
+ t.Errorf("int16(si16) != i16")
+ }
+ if int8(si8) != i8 {
+ t.Errorf("int8(si8) != i8")
+ }
+}
+
+func TestFloat32StoreToLoadConstantFold(t *testing.T) {
+ // Test that math.Float32{,from}bits constant fold correctly.
+ // In particular we need to be careful that signaling NaN (sNaN) values
+ // are not converted to quiet NaN (qNaN) values during compilation.
+ // See issue #27193 for more information.
+
+ // signaling NaNs
+ {
+ const nan = uint32(0x7f800001) // sNaN
+ if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
+ t.Errorf("got %#x, want %#x", x, nan)
+ }
+ }
+ {
+ const nan = uint32(0x7fbfffff) // sNaN
+ if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
+ t.Errorf("got %#x, want %#x", x, nan)
+ }
+ }
+ {
+ const nan = uint32(0xff800001) // sNaN
+ if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
+ t.Errorf("got %#x, want %#x", x, nan)
+ }
+ }
+ {
+ const nan = uint32(0xffbfffff) // sNaN
+ if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
+ t.Errorf("got %#x, want %#x", x, nan)
+ }
+ }
+
+ // quiet NaNs
+ {
+ const nan = uint32(0x7fc00000) // qNaN
+ if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
+ t.Errorf("got %#x, want %#x", x, nan)
+ }
+ }
+ {
+ const nan = uint32(0x7fffffff) // qNaN
+ if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
+ t.Errorf("got %#x, want %#x", x, nan)
+ }
+ }
+ {
+ const nan = uint32(0x8fc00000) // qNaN
+ if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
+ t.Errorf("got %#x, want %#x", x, nan)
+ }
+ }
+ {
+ const nan = uint32(0x8fffffff) // qNaN
+ if x := math.Float32bits(math.Float32frombits(nan)); x != nan {
+ t.Errorf("got %#x, want %#x", x, nan)
+ }
+ }
+
+ // infinities
+ {
+ const inf = uint32(0x7f800000) // +∞
+ if x := math.Float32bits(math.Float32frombits(inf)); x != inf {
+ t.Errorf("got %#x, want %#x", x, inf)
+ }
+ }
+ {
+ const negInf = uint32(0xff800000) // -∞
+ if x := math.Float32bits(math.Float32frombits(negInf)); x != negInf {
+ t.Errorf("got %#x, want %#x", x, negInf)
+ }
+ }
+
+ // numbers
+ {
+ const zero = uint32(0) // +0.0
+ if x := math.Float32bits(math.Float32frombits(zero)); x != zero {
+ t.Errorf("got %#x, want %#x", x, zero)
+ }
+ }
+ {
+ const negZero = uint32(1 << 31) // -0.0
+ if x := math.Float32bits(math.Float32frombits(negZero)); x != negZero {
+ t.Errorf("got %#x, want %#x", x, negZero)
+ }
+ }
+ {
+ const one = uint32(0x3f800000) // 1.0
+ if x := math.Float32bits(math.Float32frombits(one)); x != one {
+ t.Errorf("got %#x, want %#x", x, one)
+ }
+ }
+ {
+ const negOne = uint32(0xbf800000) // -1.0
+ if x := math.Float32bits(math.Float32frombits(negOne)); x != negOne {
+ t.Errorf("got %#x, want %#x", x, negOne)
+ }
+ }
+ {
+ const frac = uint32(0x3fc00000) // +1.5
+ if x := math.Float32bits(math.Float32frombits(frac)); x != frac {
+ t.Errorf("got %#x, want %#x", x, frac)
+ }
+ }
+ {
+ const negFrac = uint32(0xbfc00000) // -1.5
+ if x := math.Float32bits(math.Float32frombits(negFrac)); x != negFrac {
+ t.Errorf("got %#x, want %#x", x, negFrac)
+ }
+ }
+}
+
+// Signaling NaN values as constants.
+const (
+ snan32bits uint32 = 0x7f800001
+ snan64bits uint64 = 0x7ff0000000000001
+)
+
+// Signaling NaNs as variables.
+var snan32bitsVar uint32 = snan32bits
+var snan64bitsVar uint64 = snan64bits
+
+func TestFloatSignalingNaN(t *testing.T) {
+ // Make sure we generate a signaling NaN from a constant properly.
+ // See issue 36400.
+ f32 := math.Float32frombits(snan32bits)
+ g32 := math.Float32frombits(snan32bitsVar)
+ x32 := math.Float32bits(f32)
+ y32 := math.Float32bits(g32)
+ if x32 != y32 {
+ t.Errorf("got %x, want %x (diff=%x)", x32, y32, x32^y32)
+ }
+
+ f64 := math.Float64frombits(snan64bits)
+ g64 := math.Float64frombits(snan64bitsVar)
+ x64 := math.Float64bits(f64)
+ y64 := math.Float64bits(g64)
+ if x64 != y64 {
+ t.Errorf("got %x, want %x (diff=%x)", x64, y64, x64^y64)
+ }
+}
+
+func TestFloatSignalingNaNConversion(t *testing.T) {
+ // Test to make sure when we convert a signaling NaN, we get a NaN.
+ // (Ideally we want a quiet NaN, but some platforms don't agree.)
+ // See issue 36399.
+ s32 := math.Float32frombits(snan32bitsVar)
+ if s32 == s32 {
+ t.Errorf("converting a NaN did not result in a NaN")
+ }
+ s64 := math.Float64frombits(snan64bitsVar)
+ if s64 == s64 {
+ t.Errorf("converting a NaN did not result in a NaN")
+ }
+}
+
+func TestFloatSignalingNaNConversionConst(t *testing.T) {
+ // Test to make sure when we convert a signaling NaN, it converts to a NaN.
+ // (Ideally we want a quiet NaN, but some platforms don't agree.)
+ // See issue 36399 and 36400.
+ s32 := math.Float32frombits(snan32bits)
+ if s32 == s32 {
+ t.Errorf("converting a NaN did not result in a NaN")
+ }
+ s64 := math.Float64frombits(snan64bits)
+ if s64 == s64 {
+ t.Errorf("converting a NaN did not result in a NaN")
+ }
+}
+
+var sinkFloat float64
+
+func BenchmarkMul2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var m float64 = 1
+ for j := 0; j < 500; j++ {
+ m *= 2
+ }
+ sinkFloat = m
+ }
+}
+func BenchmarkMulNeg2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var m float64 = 1
+ for j := 0; j < 500; j++ {
+ m *= -2
+ }
+ sinkFloat = m
+ }
+}
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
new file mode 100644
index 0000000..f92f5d0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -0,0 +1,1986 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "bytes"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "sync"
+ "unicode/utf8"
+)
+
+// A FmtFlag value is a set of flags (or 0).
+// They control how the Xconv functions format their values.
+// See the respective function's documentation for details.
+type FmtFlag int
+
+const ( // fmt.Format flag/prec or verb
+ FmtLeft FmtFlag = 1 << iota // '-'
+ FmtSharp // '#'
+ FmtSign // '+'
+ FmtUnsigned // internal use only (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(' ') {
+ Fatalf("FmtUnsigned in format string")
+ }
+ 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
+//
+// %v Op Node opcodes
+// Flags: #: print Go syntax (automatic unless mode == FDbg)
+//
+// %j *Node Node details
+// Flags: 0: suppresses things not relevant until walk
+//
+// %v *Val Constant values
+//
+// %v *types.Sym Symbols
+// %S unqualified identifier in any mode
+// Flags: +,- #: mode (see below)
+// 0: in export mode: unqualified identifier if exported, qualified if not
+//
+// %v *types.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.
+//
+// %v *Node Nodes
+// %S (only in +/debug mode) suppress recursion
+// %L (only in Error mode) print "foo (type Bar)"
+// Flags: +,- #: mode (see below)
+//
+// %v Nodes Node lists
+// Flags: those of *Node
+// .: separate items with ',' instead of ';'
+
+// *types.Sym, *types.Type, and *Node types use the flags below to set the format mode
+const (
+ FErr fmtMode = iota
+ FDbg
+ FTypeId
+ FTypeIdName // same as FTypeId, but use package name instead of prefix
+)
+
+// The mode flags '+', '-', and '#' are sticky; they persist through
+// recursions of *Node, *types.Type, and *types.Sym values. The ' ' flag is
+// sticky only on *types.Type recursions and only used in %-/*types.Sym mode.
+//
+// Example: given a *types.Sym: %+v %#v %-v print an identifier properly qualified for debug/export/internal mode
+
+// Useful format combinations:
+// TODO(gri): verify these
+//
+// *Node, Nodes:
+// %+v multiline recursive debug dump of *Node/Nodes
+// %+S non-recursive debug dump
+//
+// *Node:
+// %#v Go format
+// %L "foo (type Bar)" for error messages
+//
+// *types.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)
+
+// update returns the results of applying f to mode.
+func (f FmtFlag) update(mode fmtMode) (FmtFlag, fmtMode) {
+ switch {
+ case f&FmtSign != 0:
+ mode = FDbg
+ case f&FmtSharp != 0:
+ // ignore (textual export format no longer supported)
+ case f&FmtUnsigned != 0:
+ mode = FTypeIdName
+ case f&FmtLeft != 0:
+ mode = FTypeId
+ }
+
+ f &^= FmtSharp | FmtLeft | FmtSign
+ return f, mode
+}
+
+var goopnames = []string{
+ OADDR: "&",
+ OADD: "+",
+ OADDSTR: "+",
+ OALIGNOF: "unsafe.Alignof",
+ OANDAND: "&&",
+ OANDNOT: "&^",
+ OAND: "&",
+ OAPPEND: "append",
+ OAS: "=",
+ OAS2: "=",
+ OBREAK: "break",
+ OCALL: "function call", // not actual syntax
+ OCAP: "cap",
+ OCASE: "case",
+ OCLOSE: "close",
+ OCOMPLEX: "complex",
+ OBITNOT: "^",
+ OCONTINUE: "continue",
+ OCOPY: "copy",
+ ODELETE: "delete",
+ ODEFER: "defer",
+ ODIV: "/",
+ OEQ: "==",
+ OFALL: "fallthrough",
+ OFOR: "for",
+ OFORUNTIL: "foruntil", // not actual syntax; used to avoid off-end pointer live on backedge.892
+ OGE: ">=",
+ OGOTO: "goto",
+ OGT: ">",
+ OIF: "if",
+ OIMAG: "imag",
+ OINLMARK: "inlmark",
+ ODEREF: "*",
+ OLEN: "len",
+ OLE: "<=",
+ OLSH: "<<",
+ OLT: "<",
+ OMAKE: "make",
+ ONEG: "-",
+ OMOD: "%",
+ OMUL: "*",
+ ONEW: "new",
+ ONE: "!=",
+ ONOT: "!",
+ OOFFSETOF: "unsafe.Offsetof",
+ OOROR: "||",
+ OOR: "|",
+ OPANIC: "panic",
+ OPLUS: "+",
+ OPRINTN: "println",
+ OPRINT: "print",
+ ORANGE: "range",
+ OREAL: "real",
+ ORECV: "<-",
+ ORECOVER: "recover",
+ ORETURN: "return",
+ ORSH: ">>",
+ OSELECT: "select",
+ OSEND: "<-",
+ OSIZEOF: "unsafe.Sizeof",
+ OSUB: "-",
+ OSWITCH: "switch",
+ OXOR: "^",
+}
+
+func (o Op) GoString() string {
+ return fmt.Sprintf("%#v", o)
+}
+
+func (o Op) format(s fmt.State, verb rune, mode fmtMode) {
+ switch verb {
+ case 'v':
+ o.oconv(s, fmtFlag(s, verb), mode)
+
+ default:
+ fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o))
+ }
+}
+
+func (o Op) oconv(s fmt.State, flag FmtFlag, mode fmtMode) {
+ if flag&FmtSharp != 0 || mode != FDbg {
+ if int(o) < len(goopnames) && goopnames[o] != "" {
+ fmt.Fprint(s, goopnames[o])
+ return
+ }
+ }
+
+ // 'o.String()' instead of just 'o' to avoid infinite recursion
+ fmt.Fprint(s, o.String())
+}
+
+type (
+ fmtMode int
+
+ fmtNodeErr Node
+ fmtNodeDbg Node
+ fmtNodeTypeId Node
+ fmtNodeTypeIdName Node
+
+ fmtOpErr Op
+ fmtOpDbg Op
+ fmtOpTypeId Op
+ fmtOpTypeIdName Op
+
+ fmtTypeErr types.Type
+ fmtTypeDbg types.Type
+ fmtTypeTypeId types.Type
+ fmtTypeTypeIdName types.Type
+
+ fmtSymErr types.Sym
+ fmtSymDbg types.Sym
+ fmtSymTypeId types.Sym
+ fmtSymTypeIdName types.Sym
+
+ fmtNodesErr Nodes
+ fmtNodesDbg Nodes
+ fmtNodesTypeId Nodes
+ fmtNodesTypeIdName Nodes
+)
+
+func (n *fmtNodeErr) Format(s fmt.State, verb rune) { (*Node)(n).format(s, verb, FErr) }
+func (n *fmtNodeDbg) Format(s fmt.State, verb rune) { (*Node)(n).format(s, verb, FDbg) }
+func (n *fmtNodeTypeId) Format(s fmt.State, verb rune) { (*Node)(n).format(s, verb, FTypeId) }
+func (n *fmtNodeTypeIdName) Format(s fmt.State, verb rune) { (*Node)(n).format(s, verb, FTypeIdName) }
+func (n *Node) Format(s fmt.State, verb rune) { n.format(s, verb, FErr) }
+
+func (o fmtOpErr) Format(s fmt.State, verb rune) { Op(o).format(s, verb, FErr) }
+func (o fmtOpDbg) Format(s fmt.State, verb rune) { Op(o).format(s, verb, FDbg) }
+func (o fmtOpTypeId) Format(s fmt.State, verb rune) { Op(o).format(s, verb, FTypeId) }
+func (o fmtOpTypeIdName) Format(s fmt.State, verb rune) { Op(o).format(s, verb, FTypeIdName) }
+func (o Op) Format(s fmt.State, verb rune) { o.format(s, verb, FErr) }
+
+func (t *fmtTypeErr) Format(s fmt.State, verb rune) { typeFormat((*types.Type)(t), s, verb, FErr) }
+func (t *fmtTypeDbg) Format(s fmt.State, verb rune) { typeFormat((*types.Type)(t), s, verb, FDbg) }
+func (t *fmtTypeTypeId) Format(s fmt.State, verb rune) {
+ typeFormat((*types.Type)(t), s, verb, FTypeId)
+}
+func (t *fmtTypeTypeIdName) Format(s fmt.State, verb rune) {
+ typeFormat((*types.Type)(t), s, verb, FTypeIdName)
+}
+
+// func (t *types.Type) Format(s fmt.State, verb rune) // in package types
+
+func (y *fmtSymErr) Format(s fmt.State, verb rune) { symFormat((*types.Sym)(y), s, verb, FErr) }
+func (y *fmtSymDbg) Format(s fmt.State, verb rune) { symFormat((*types.Sym)(y), s, verb, FDbg) }
+func (y *fmtSymTypeId) Format(s fmt.State, verb rune) { symFormat((*types.Sym)(y), s, verb, FTypeId) }
+func (y *fmtSymTypeIdName) Format(s fmt.State, verb rune) {
+ symFormat((*types.Sym)(y), s, verb, FTypeIdName)
+}
+
+// func (y *types.Sym) Format(s fmt.State, verb rune) // in package types { y.format(s, verb, FErr) }
+
+func (n fmtNodesErr) Format(s fmt.State, verb rune) { (Nodes)(n).format(s, verb, FErr) }
+func (n fmtNodesDbg) Format(s fmt.State, verb rune) { (Nodes)(n).format(s, verb, FDbg) }
+func (n fmtNodesTypeId) Format(s fmt.State, verb rune) { (Nodes)(n).format(s, verb, FTypeId) }
+func (n fmtNodesTypeIdName) Format(s fmt.State, verb rune) { (Nodes)(n).format(s, verb, FTypeIdName) }
+func (n Nodes) Format(s fmt.State, verb rune) { n.format(s, verb, FErr) }
+
+func (m fmtMode) Fprintf(s fmt.State, format string, args ...interface{}) {
+ m.prepareArgs(args)
+ fmt.Fprintf(s, format, args...)
+}
+
+func (m fmtMode) Sprintf(format string, args ...interface{}) string {
+ m.prepareArgs(args)
+ return fmt.Sprintf(format, args...)
+}
+
+func (m fmtMode) Sprint(args ...interface{}) string {
+ m.prepareArgs(args)
+ return fmt.Sprint(args...)
+}
+
+func (m fmtMode) prepareArgs(args []interface{}) {
+ switch m {
+ case FErr:
+ for i, arg := range args {
+ switch arg := arg.(type) {
+ case Op:
+ args[i] = fmtOpErr(arg)
+ case *Node:
+ args[i] = (*fmtNodeErr)(arg)
+ case *types.Type:
+ args[i] = (*fmtTypeErr)(arg)
+ case *types.Sym:
+ args[i] = (*fmtSymErr)(arg)
+ case Nodes:
+ args[i] = fmtNodesErr(arg)
+ case Val, int32, int64, string, types.EType:
+ // OK: printing these types doesn't depend on mode
+ default:
+ Fatalf("mode.prepareArgs type %T", arg)
+ }
+ }
+ case FDbg:
+ for i, arg := range args {
+ switch arg := arg.(type) {
+ case Op:
+ args[i] = fmtOpDbg(arg)
+ case *Node:
+ args[i] = (*fmtNodeDbg)(arg)
+ case *types.Type:
+ args[i] = (*fmtTypeDbg)(arg)
+ case *types.Sym:
+ args[i] = (*fmtSymDbg)(arg)
+ case Nodes:
+ args[i] = fmtNodesDbg(arg)
+ case Val, int32, int64, string, types.EType:
+ // OK: printing these types doesn't depend on mode
+ default:
+ Fatalf("mode.prepareArgs type %T", arg)
+ }
+ }
+ case FTypeId:
+ for i, arg := range args {
+ switch arg := arg.(type) {
+ case Op:
+ args[i] = fmtOpTypeId(arg)
+ case *Node:
+ args[i] = (*fmtNodeTypeId)(arg)
+ case *types.Type:
+ args[i] = (*fmtTypeTypeId)(arg)
+ case *types.Sym:
+ args[i] = (*fmtSymTypeId)(arg)
+ case Nodes:
+ args[i] = fmtNodesTypeId(arg)
+ case Val, int32, int64, string, types.EType:
+ // OK: printing these types doesn't depend on mode
+ default:
+ Fatalf("mode.prepareArgs type %T", arg)
+ }
+ }
+ case FTypeIdName:
+ for i, arg := range args {
+ switch arg := arg.(type) {
+ case Op:
+ args[i] = fmtOpTypeIdName(arg)
+ case *Node:
+ args[i] = (*fmtNodeTypeIdName)(arg)
+ case *types.Type:
+ args[i] = (*fmtTypeTypeIdName)(arg)
+ case *types.Sym:
+ args[i] = (*fmtSymTypeIdName)(arg)
+ case Nodes:
+ args[i] = fmtNodesTypeIdName(arg)
+ case Val, int32, int64, string, types.EType:
+ // OK: printing these types doesn't depend on mode
+ default:
+ Fatalf("mode.prepareArgs type %T", arg)
+ }
+ }
+ default:
+ Fatalf("mode.prepareArgs mode %d", m)
+ }
+}
+
+func (n *Node) format(s fmt.State, verb rune, mode fmtMode) {
+ switch verb {
+ case 'v', 'S', 'L':
+ n.nconv(s, fmtFlag(s, verb), mode)
+
+ 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
+
+ // Useful to see which nodes in a Node Dump/dumplist are actually identical
+ if Debug_dumpptrs != 0 {
+ fmt.Fprintf(s, " p(%p)", n)
+ }
+ if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
+ fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
+ }
+
+ if Debug_dumpptrs != 0 && c == 0 && n.Name != nil && n.Name.Defn != nil {
+ // Useful to see where Defn is set and what node it points to
+ fmt.Fprintf(s, " defn(%p)", n.Name.Defn)
+ }
+
+ if n.Pos.IsKnown() {
+ pfx := ""
+ switch n.Pos.IsStmt() {
+ case src.PosNotStmt:
+ pfx = "_" // "-" would be confusing
+ case src.PosIsStmt:
+ pfx = "+"
+ }
+ fmt.Fprintf(s, " l(%s%d)", pfx, n.Pos.Line())
+ }
+
+ if c == 0 && n.Xoffset != BADWIDTH {
+ fmt.Fprintf(s, " x(%d)", n.Xoffset)
+ }
+
+ if n.Class() != 0 {
+ fmt.Fprintf(s, " class(%v)", n.Class())
+ }
+
+ if n.Colas() {
+ fmt.Fprintf(s, " colas(%v)", n.Colas())
+ }
+
+ switch n.Esc {
+ case EscUnknown:
+ break
+
+ case EscHeap:
+ fmt.Fprint(s, " esc(h)")
+
+ case EscNone:
+ fmt.Fprint(s, " esc(no)")
+
+ case EscNever:
+ if c == 0 {
+ fmt.Fprint(s, " esc(N)")
+ }
+
+ default:
+ fmt.Fprintf(s, " esc(%d)", n.Esc)
+ }
+
+ if e, ok := n.Opt().(*EscLocation); ok && e.loopDepth != 0 {
+ fmt.Fprintf(s, " ld(%d)", e.loopDepth)
+ }
+
+ if c == 0 && n.Typecheck() != 0 {
+ fmt.Fprintf(s, " tc(%d)", n.Typecheck())
+ }
+
+ if n.IsDDD() {
+ fmt.Fprintf(s, " isddd(%v)", n.IsDDD())
+ }
+
+ if n.Implicit() {
+ fmt.Fprintf(s, " implicit(%v)", n.Implicit())
+ }
+
+ if n.Embedded() {
+ fmt.Fprintf(s, " embedded")
+ }
+
+ if n.Op == ONAME {
+ if n.Name.Addrtaken() {
+ fmt.Fprint(s, " addrtaken")
+ }
+ if n.Name.Assigned() {
+ fmt.Fprint(s, " assigned")
+ }
+ if n.Name.IsClosureVar() {
+ fmt.Fprint(s, " closurevar")
+ }
+ if n.Name.Captured() {
+ fmt.Fprint(s, " captured")
+ }
+ if n.Name.IsOutputParamHeapAddr() {
+ fmt.Fprint(s, " outputparamheapaddr")
+ }
+ }
+ if n.Bounded() {
+ fmt.Fprint(s, " bounded")
+ }
+ if n.NonNil() {
+ fmt.Fprint(s, " nonnil")
+ }
+
+ if c == 0 && n.HasCall() {
+ fmt.Fprint(s, " hascall")
+ }
+
+ if c == 0 && n.Name != nil && n.Name.Used() {
+ fmt.Fprint(s, " 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)
+ }
+}
+
+func (v Val) vconv(s fmt.State, flag FmtFlag) {
+ switch u := v.U.(type) {
+ case *Mpint:
+ if !u.Rune {
+ if flag&FmtSharp != 0 {
+ fmt.Fprint(s, u.String())
+ return
+ }
+ fmt.Fprint(s, u.GoString())
+ return
+ }
+
+ 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)
+ }
+
+ case *Mpflt:
+ if flag&FmtSharp != 0 {
+ fmt.Fprint(s, u.String())
+ return
+ }
+ fmt.Fprint(s, u.GoString())
+ return
+
+ case *Mpcplx:
+ if flag&FmtSharp != 0 {
+ fmt.Fprint(s, u.String())
+ return
+ }
+ fmt.Fprint(s, u.GoString())
+ return
+
+ case string:
+ fmt.Fprint(s, strconv.Quote(u))
+
+ case bool:
+ fmt.Fprint(s, u)
+
+ case *NilVal:
+ fmt.Fprint(s, "nil")
+
+ default:
+ fmt.Fprintf(s, "<ctype=%d>", v.Ctype())
+ }
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ ]*T%%g
+s%,.*%%g
+s%.+% [T&] = "&",%g
+s%^ ........*\]%&~%g
+s%~ %%g
+*/
+
+func symfmt(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode fmtMode) {
+ if flag&FmtShort == 0 {
+ switch mode {
+ case FErr: // This is for the user
+ if s.Pkg == builtinpkg || s.Pkg == localpkg {
+ b.WriteString(s.Name)
+ return
+ }
+
+ // If the name was used by multiple packages, display the full path,
+ if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
+ fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name)
+ return
+ }
+ b.WriteString(s.Pkg.Name)
+ b.WriteByte('.')
+ b.WriteString(s.Name)
+ return
+
+ case FDbg:
+ b.WriteString(s.Pkg.Name)
+ b.WriteByte('.')
+ b.WriteString(s.Name)
+ return
+
+ case FTypeIdName:
+ // dcommontype, typehash
+ b.WriteString(s.Pkg.Name)
+ b.WriteByte('.')
+ b.WriteString(s.Name)
+ return
+
+ case FTypeId:
+ // (methodsym), typesym, weaksym
+ b.WriteString(s.Pkg.Prefix)
+ b.WriteByte('.')
+ b.WriteString(s.Name)
+ return
+ }
+ }
+
+ if flag&FmtByte != 0 {
+ // FmtByte (hh) implies FmtShort (h)
+ // skip leading "type." in method name
+ name := s.Name
+ if i := strings.LastIndex(name, "."); i >= 0 {
+ name = name[i+1:]
+ }
+
+ if mode == FDbg {
+ fmt.Fprintf(b, "@%q.%s", s.Pkg.Path, name)
+ return
+ }
+
+ b.WriteString(name)
+ return
+ }
+
+ b.WriteString(s.Name)
+}
+
+var basicnames = []string{
+ TINT: "int",
+ TUINT: "uint",
+ TINT8: "int8",
+ TUINT8: "uint8",
+ TINT16: "int16",
+ TUINT16: "uint16",
+ TINT32: "int32",
+ TUINT32: "uint32",
+ TINT64: "int64",
+ TUINT64: "uint64",
+ TUINTPTR: "uintptr",
+ TFLOAT32: "float32",
+ TFLOAT64: "float64",
+ TCOMPLEX64: "complex64",
+ TCOMPLEX128: "complex128",
+ TBOOL: "bool",
+ TANY: "any",
+ TSTRING: "string",
+ TNIL: "nil",
+ TIDEAL: "untyped number",
+ TBLANK: "blank",
+}
+
+var fmtBufferPool = sync.Pool{
+ New: func() interface{} {
+ return new(bytes.Buffer)
+ },
+}
+
+func tconv(t *types.Type, flag FmtFlag, mode fmtMode) string {
+ buf := fmtBufferPool.Get().(*bytes.Buffer)
+ buf.Reset()
+ defer fmtBufferPool.Put(buf)
+
+ tconv2(buf, t, flag, mode, nil)
+ return types.InternString(buf.Bytes())
+}
+
+// tconv2 writes a string representation of t to b.
+// flag and mode control exactly what is printed.
+// Any types x that are already in the visited map get printed as @%d where %d=visited[x].
+// See #16897 before changing the implementation of tconv.
+func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited map[*types.Type]int) {
+ if off, ok := visited[t]; ok {
+ // We've seen this type before, so we're trying to print it recursively.
+ // Print a reference to it instead.
+ fmt.Fprintf(b, "@%d", off)
+ return
+ }
+ if t == nil {
+ b.WriteString("<T>")
+ return
+ }
+ if t.Etype == types.TSSA {
+ b.WriteString(t.Extra.(string))
+ return
+ }
+ if t.Etype == types.TTUPLE {
+ b.WriteString(t.FieldType(0).String())
+ b.WriteByte(',')
+ b.WriteString(t.FieldType(1).String())
+ return
+ }
+
+ if t.Etype == types.TRESULTS {
+ tys := t.Extra.(*types.Results).Types
+ for i, et := range tys {
+ if i > 0 {
+ b.WriteByte(',')
+ }
+ b.WriteString(et.String())
+ }
+ return
+ }
+
+ flag, mode = flag.update(mode)
+ if mode == FTypeIdName {
+ flag |= FmtUnsigned
+ }
+ if t == types.Bytetype || t == types.Runetype {
+ // in %-T mode collapse rune and byte with their originals.
+ switch mode {
+ case FTypeIdName, FTypeId:
+ t = types.Types[t.Etype]
+ default:
+ sconv2(b, t.Sym, FmtShort, mode)
+ return
+ }
+ }
+ if t == types.Errortype {
+ b.WriteString("error")
+ return
+ }
+
+ // Unless the 'L' flag was specified, if the type has a name, just print that name.
+ if flag&FmtLong == 0 && t.Sym != nil && t != types.Types[t.Etype] {
+ switch mode {
+ case FTypeId, FTypeIdName:
+ if flag&FmtShort != 0 {
+ if t.Vargen != 0 {
+ sconv2(b, t.Sym, FmtShort, mode)
+ fmt.Fprintf(b, "·%d", t.Vargen)
+ return
+ }
+ sconv2(b, t.Sym, FmtShort, mode)
+ return
+ }
+
+ if mode == FTypeIdName {
+ sconv2(b, t.Sym, FmtUnsigned, mode)
+ return
+ }
+
+ if t.Sym.Pkg == localpkg && t.Vargen != 0 {
+ b.WriteString(mode.Sprintf("%v·%d", t.Sym, t.Vargen))
+ return
+ }
+ }
+
+ sconv2(b, t.Sym, 0, mode)
+ return
+ }
+
+ if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
+ var name string
+ switch t {
+ case types.UntypedBool:
+ name = "untyped bool"
+ case types.UntypedString:
+ name = "untyped string"
+ case types.UntypedInt:
+ name = "untyped int"
+ case types.UntypedRune:
+ name = "untyped rune"
+ case types.UntypedFloat:
+ name = "untyped float"
+ case types.UntypedComplex:
+ name = "untyped complex"
+ default:
+ name = basicnames[t.Etype]
+ }
+ b.WriteString(name)
+ return
+ }
+
+ if mode == FDbg {
+ b.WriteString(t.Etype.String())
+ b.WriteByte('-')
+ tconv2(b, t, flag, FErr, visited)
+ return
+ }
+
+ // At this point, we might call tconv2 recursively. Add the current type to the visited list so we don't
+ // try to print it recursively.
+ // We record the offset in the result buffer where the type's text starts. This offset serves as a reference
+ // point for any later references to the same type.
+ // Note that we remove the type from the visited map as soon as the recursive call is done.
+ // This prevents encoding types like map[*int]*int as map[*int]@4. (That encoding would work,
+ // but I'd like to use the @ notation only when strictly necessary.)
+ if visited == nil {
+ visited = map[*types.Type]int{}
+ }
+ visited[t] = b.Len()
+ defer delete(visited, t)
+
+ switch t.Etype {
+ case TPTR:
+ b.WriteByte('*')
+ switch mode {
+ case FTypeId, FTypeIdName:
+ if flag&FmtShort != 0 {
+ tconv2(b, t.Elem(), FmtShort, mode, visited)
+ return
+ }
+ }
+ tconv2(b, t.Elem(), 0, mode, visited)
+
+ case TARRAY:
+ b.WriteByte('[')
+ b.WriteString(strconv.FormatInt(t.NumElem(), 10))
+ b.WriteByte(']')
+ tconv2(b, t.Elem(), 0, mode, visited)
+
+ case TSLICE:
+ b.WriteString("[]")
+ tconv2(b, t.Elem(), 0, mode, visited)
+
+ case TCHAN:
+ switch t.ChanDir() {
+ case types.Crecv:
+ b.WriteString("<-chan ")
+ tconv2(b, t.Elem(), 0, mode, visited)
+ case types.Csend:
+ b.WriteString("chan<- ")
+ tconv2(b, t.Elem(), 0, mode, visited)
+ default:
+ b.WriteString("chan ")
+ if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == types.Crecv {
+ b.WriteByte('(')
+ tconv2(b, t.Elem(), 0, mode, visited)
+ b.WriteByte(')')
+ } else {
+ tconv2(b, t.Elem(), 0, mode, visited)
+ }
+ }
+
+ case TMAP:
+ b.WriteString("map[")
+ tconv2(b, t.Key(), 0, mode, visited)
+ b.WriteByte(']')
+ tconv2(b, t.Elem(), 0, mode, visited)
+
+ case TINTER:
+ if t.IsEmptyInterface() {
+ b.WriteString("interface {}")
+ break
+ }
+ b.WriteString("interface {")
+ for i, f := range t.Fields().Slice() {
+ if i != 0 {
+ b.WriteByte(';')
+ }
+ b.WriteByte(' ')
+ 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 types.IsExported(f.Sym.Name):
+ sconv2(b, f.Sym, FmtShort, mode)
+ default:
+ flag1 := FmtLeft
+ if flag&FmtUnsigned != 0 {
+ flag1 = FmtUnsigned
+ }
+ sconv2(b, f.Sym, flag1, mode)
+ }
+ tconv2(b, f.Type, FmtShort, mode, visited)
+ }
+ if t.NumFields() != 0 {
+ b.WriteByte(' ')
+ }
+ b.WriteByte('}')
+
+ case TFUNC:
+ if flag&FmtShort != 0 {
+ // no leading func
+ } else {
+ if t.Recv() != nil {
+ b.WriteString("method")
+ tconv2(b, t.Recvs(), 0, mode, visited)
+ b.WriteByte(' ')
+ }
+ b.WriteString("func")
+ }
+ tconv2(b, t.Params(), 0, mode, visited)
+
+ switch t.NumResults() {
+ case 0:
+ // nothing to do
+
+ case 1:
+ b.WriteByte(' ')
+ tconv2(b, t.Results().Field(0).Type, 0, mode, visited) // struct->field->field's type
+
+ default:
+ b.WriteByte(' ')
+ tconv2(b, t.Results(), 0, mode, visited)
+ }
+
+ case TSTRUCT:
+ if m := t.StructType().Map; m != nil {
+ mt := m.MapType()
+ // Format the bucket struct for map[x]y as map.bucket[x]y.
+ // This avoids a recursive print that generates very long names.
+ switch t {
+ case mt.Bucket:
+ b.WriteString("map.bucket[")
+ case mt.Hmap:
+ b.WriteString("map.hdr[")
+ case mt.Hiter:
+ b.WriteString("map.iter[")
+ default:
+ Fatalf("unknown internal map type")
+ }
+ tconv2(b, m.Key(), 0, mode, visited)
+ b.WriteByte(']')
+ tconv2(b, m.Elem(), 0, mode, visited)
+ break
+ }
+
+ if funarg := t.StructType().Funarg; funarg != types.FunargNone {
+ b.WriteByte('(')
+ var flag1 FmtFlag
+ switch mode {
+ case FTypeId, FTypeIdName, FErr:
+ // no argument names on function signature, and no "noescape"/"nosplit" tags
+ flag1 = FmtShort
+ }
+ for i, f := range t.Fields().Slice() {
+ if i != 0 {
+ b.WriteString(", ")
+ }
+ fldconv(b, f, flag1, mode, visited, funarg)
+ }
+ b.WriteByte(')')
+ } else {
+ b.WriteString("struct {")
+ for i, f := range t.Fields().Slice() {
+ if i != 0 {
+ b.WriteByte(';')
+ }
+ b.WriteByte(' ')
+ fldconv(b, f, FmtLong, mode, visited, funarg)
+ }
+ if t.NumFields() != 0 {
+ b.WriteByte(' ')
+ }
+ b.WriteByte('}')
+ }
+
+ case TFORW:
+ b.WriteString("undefined")
+ if t.Sym != nil {
+ b.WriteByte(' ')
+ sconv2(b, t.Sym, 0, mode)
+ }
+
+ case TUNSAFEPTR:
+ b.WriteString("unsafe.Pointer")
+
+ case Txxx:
+ b.WriteString("Txxx")
+ default:
+ // Don't know how to handle - fall back to detailed prints.
+ b.WriteString(mode.Sprintf("%v <%v>", t.Etype, t.Sym))
+ }
+}
+
+// Statements which may be rendered with a simplestmt as init.
+func stmtwithinit(op Op) bool {
+ switch op {
+ case OIF, OFOR, OFORUNTIL, OSWITCH:
+ return true
+ }
+
+ return false
+}
+
+func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
+ // some statements allow for an init, but at most one,
+ // but we may have an arbitrary number added, eg by typecheck
+ // and inlining. If it doesn't fit the syntax, emit an enclosing
+ // block starting with the init statements.
+
+ // if we can just say "for" n->ninit; ... then do so
+ simpleinit := n.Ninit.Len() == 1 && n.Ninit.First().Ninit.Len() == 0 && stmtwithinit(n.Op)
+
+ // otherwise, print the inits as separate statements
+ complexinit := n.Ninit.Len() != 0 && !simpleinit && (mode != FErr)
+
+ // but if it was for if/for/switch, put in an extra surrounding block to limit the scope
+ extrablock := complexinit && stmtwithinit(n.Op)
+
+ if extrablock {
+ fmt.Fprint(s, "{")
+ }
+
+ if complexinit {
+ mode.Fprintf(s, " %v; ", n.Ninit)
+ }
+
+ switch n.Op {
+ case ODCL:
+ mode.Fprintf(s, "var %v %v", n.Left.Sym, n.Left.Type)
+
+ case ODCLFIELD:
+ if n.Sym != nil {
+ mode.Fprintf(s, "%v %v", n.Sym, n.Left)
+ } else {
+ mode.Fprintf(s, "%v", n.Left)
+ }
+
+ // 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:
+ if n.Colas() && !complexinit {
+ mode.Fprintf(s, "%v := %v", n.Left, n.Right)
+ } else {
+ mode.Fprintf(s, "%v = %v", n.Left, n.Right)
+ }
+
+ case OASOP:
+ if n.Implicit() {
+ if n.SubOp() == OADD {
+ mode.Fprintf(s, "%v++", n.Left)
+ } else {
+ mode.Fprintf(s, "%v--", n.Left)
+ }
+ break
+ }
+
+ mode.Fprintf(s, "%v %#v= %v", n.Left, n.SubOp(), n.Right)
+
+ case OAS2:
+ if n.Colas() && !complexinit {
+ mode.Fprintf(s, "%.v := %.v", n.List, n.Rlist)
+ break
+ }
+ fallthrough
+
+ case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ mode.Fprintf(s, "%.v = %v", n.List, n.Right)
+
+ case ORETURN:
+ mode.Fprintf(s, "return %.v", n.List)
+
+ case ORETJMP:
+ mode.Fprintf(s, "retjmp %v", n.Sym)
+
+ case OINLMARK:
+ mode.Fprintf(s, "inlmark %d", n.Xoffset)
+
+ case OGO:
+ mode.Fprintf(s, "go %v", n.Left)
+
+ case ODEFER:
+ mode.Fprintf(s, "defer %v", n.Left)
+
+ case OIF:
+ if simpleinit {
+ mode.Fprintf(s, "if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody)
+ } else {
+ mode.Fprintf(s, "if %v { %v }", n.Left, n.Nbody)
+ }
+ if n.Rlist.Len() != 0 {
+ mode.Fprintf(s, " else { %v }", n.Rlist)
+ }
+
+ case OFOR, OFORUNTIL:
+ opname := "for"
+ if n.Op == OFORUNTIL {
+ opname = "foruntil"
+ }
+ if mode == FErr { // TODO maybe only if FmtShort, same below
+ fmt.Fprintf(s, "%s loop", opname)
+ break
+ }
+
+ fmt.Fprint(s, opname)
+ if simpleinit {
+ mode.Fprintf(s, " %v;", n.Ninit.First())
+ } else if n.Right != nil {
+ fmt.Fprint(s, " ;")
+ }
+
+ if n.Left != nil {
+ mode.Fprintf(s, " %v", n.Left)
+ }
+
+ if n.Right != nil {
+ mode.Fprintf(s, "; %v", n.Right)
+ } else if simpleinit {
+ fmt.Fprint(s, ";")
+ }
+
+ if n.Op == OFORUNTIL && n.List.Len() != 0 {
+ mode.Fprintf(s, "; %v", n.List)
+ }
+
+ mode.Fprintf(s, " { %v }", n.Nbody)
+
+ case ORANGE:
+ if mode == FErr {
+ fmt.Fprint(s, "for loop")
+ break
+ }
+
+ if n.List.Len() == 0 {
+ mode.Fprintf(s, "for range %v { %v }", n.Right, n.Nbody)
+ break
+ }
+
+ mode.Fprintf(s, "for %.v = range %v { %v }", n.List, n.Right, n.Nbody)
+
+ case OSELECT, OSWITCH:
+ if mode == FErr {
+ mode.Fprintf(s, "%v statement", n.Op)
+ break
+ }
+
+ mode.Fprintf(s, "%#v", n.Op)
+ if simpleinit {
+ mode.Fprintf(s, " %v;", n.Ninit.First())
+ }
+ if n.Left != nil {
+ mode.Fprintf(s, " %v ", n.Left)
+ }
+
+ mode.Fprintf(s, " { %v }", n.List)
+
+ case OCASE:
+ if n.List.Len() != 0 {
+ mode.Fprintf(s, "case %.v", n.List)
+ } else {
+ fmt.Fprint(s, "default")
+ }
+ mode.Fprintf(s, ": %v", n.Nbody)
+
+ case OBREAK, OCONTINUE, OGOTO, OFALL:
+ if n.Sym != nil {
+ mode.Fprintf(s, "%#v %v", n.Op, n.Sym)
+ } else {
+ mode.Fprintf(s, "%#v", n.Op)
+ }
+
+ case OEMPTY:
+ break
+
+ case OLABEL:
+ mode.Fprintf(s, "%v: ", n.Sym)
+ }
+
+ if extrablock {
+ fmt.Fprint(s, "}")
+ }
+}
+
+var opprec = []int{
+ OALIGNOF: 8,
+ OAPPEND: 8,
+ OBYTES2STR: 8,
+ OARRAYLIT: 8,
+ OSLICELIT: 8,
+ ORUNES2STR: 8,
+ OCALLFUNC: 8,
+ OCALLINTER: 8,
+ OCALLMETH: 8,
+ OCALL: 8,
+ OCAP: 8,
+ OCLOSE: 8,
+ OCONVIFACE: 8,
+ OCONVNOP: 8,
+ OCONV: 8,
+ OCOPY: 8,
+ ODELETE: 8,
+ OGETG: 8,
+ OLEN: 8,
+ OLITERAL: 8,
+ OMAKESLICE: 8,
+ OMAKESLICECOPY: 8,
+ OMAKE: 8,
+ OMAPLIT: 8,
+ ONAME: 8,
+ ONEW: 8,
+ ONONAME: 8,
+ OOFFSETOF: 8,
+ OPACK: 8,
+ OPANIC: 8,
+ OPAREN: 8,
+ OPRINTN: 8,
+ OPRINT: 8,
+ ORUNESTR: 8,
+ OSIZEOF: 8,
+ OSTR2BYTES: 8,
+ OSTR2RUNES: 8,
+ OSTRUCTLIT: 8,
+ OTARRAY: 8,
+ OTCHAN: 8,
+ OTFUNC: 8,
+ OTINTER: 8,
+ OTMAP: 8,
+ OTSTRUCT: 8,
+ OINDEXMAP: 8,
+ OINDEX: 8,
+ OSLICE: 8,
+ OSLICESTR: 8,
+ OSLICEARR: 8,
+ OSLICE3: 8,
+ OSLICE3ARR: 8,
+ OSLICEHEADER: 8,
+ ODOTINTER: 8,
+ ODOTMETH: 8,
+ ODOTPTR: 8,
+ ODOTTYPE2: 8,
+ ODOTTYPE: 8,
+ ODOT: 8,
+ OXDOT: 8,
+ OCALLPART: 8,
+ OPLUS: 7,
+ ONOT: 7,
+ OBITNOT: 7,
+ ONEG: 7,
+ OADDR: 7,
+ ODEREF: 7,
+ ORECV: 7,
+ OMUL: 6,
+ ODIV: 6,
+ OMOD: 6,
+ OLSH: 6,
+ ORSH: 6,
+ OAND: 6,
+ OANDNOT: 6,
+ OADD: 5,
+ OSUB: 5,
+ OOR: 5,
+ OXOR: 5,
+ OEQ: 4,
+ OLT: 4,
+ OLE: 4,
+ OGE: 4,
+ OGT: 4,
+ ONE: 4,
+ OSEND: 3,
+ OANDAND: 2,
+ OOROR: 1,
+
+ // Statements handled by stmtfmt
+ OAS: -1,
+ OAS2: -1,
+ OAS2DOTTYPE: -1,
+ OAS2FUNC: -1,
+ OAS2MAPR: -1,
+ OAS2RECV: -1,
+ OASOP: -1,
+ OBREAK: -1,
+ OCASE: -1,
+ OCONTINUE: -1,
+ ODCL: -1,
+ ODCLFIELD: -1,
+ ODEFER: -1,
+ OEMPTY: -1,
+ OFALL: -1,
+ OFOR: -1,
+ OFORUNTIL: -1,
+ OGOTO: -1,
+ OIF: -1,
+ OLABEL: -1,
+ OGO: -1,
+ ORANGE: -1,
+ ORETURN: -1,
+ OSELECT: -1,
+ OSWITCH: -1,
+
+ OEND: 0,
+}
+
+func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
+ for n != nil && n.Implicit() && (n.Op == ODEREF || n.Op == OADDR) {
+ n = n.Left
+ }
+
+ if n == nil {
+ fmt.Fprint(s, "<N>")
+ return
+ }
+
+ nprec := opprec[n.Op]
+ if n.Op == OTYPE && n.Sym != nil {
+ nprec = 8
+ }
+
+ if prec > nprec {
+ mode.Fprintf(s, "(%v)", n)
+ return
+ }
+
+ switch n.Op {
+ case OPAREN:
+ mode.Fprintf(s, "(%v)", n.Left)
+
+ case OLITERAL: // this is a bit of a mess
+ if mode == FErr {
+ if n.Orig != nil && n.Orig != n {
+ n.Orig.exprfmt(s, prec, mode)
+ return
+ }
+ if n.Sym != nil {
+ fmt.Fprint(s, smodeString(n.Sym, mode))
+ return
+ }
+ }
+ if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
+ n.Orig.exprfmt(s, prec, mode)
+ return
+ }
+ if n.Type != nil && !n.Type.IsUntyped() {
+ // 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() == types.Crecv) {
+ mode.Fprintf(s, "(%v)(%v)", n.Type, n.Val())
+ return
+ } else {
+ mode.Fprintf(s, "%v(%v)", n.Type, n.Val())
+ return
+ }
+ }
+
+ mode.Fprintf(s, "%v", n.Val())
+
+ // Special case: name used as local variable in export.
+ // _ becomes ~b%d internally; print as _ for export
+ case ONAME:
+ if mode == FErr && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
+ fmt.Fprint(s, "_")
+ return
+ }
+ fallthrough
+ case OPACK, ONONAME:
+ fmt.Fprint(s, smodeString(n.Sym, mode))
+
+ case OTYPE:
+ if n.Type == nil && n.Sym != nil {
+ fmt.Fprint(s, smodeString(n.Sym, mode))
+ return
+ }
+ mode.Fprintf(s, "%v", n.Type)
+
+ case OTARRAY:
+ if n.Left != nil {
+ mode.Fprintf(s, "[%v]%v", n.Left, n.Right)
+ return
+ }
+ mode.Fprintf(s, "[]%v", n.Right) // happens before typecheck
+
+ case OTMAP:
+ mode.Fprintf(s, "map[%v]%v", n.Left, n.Right)
+
+ case OTCHAN:
+ switch n.TChanDir() {
+ case types.Crecv:
+ mode.Fprintf(s, "<-chan %v", n.Left)
+
+ case types.Csend:
+ mode.Fprintf(s, "chan<- %v", n.Left)
+
+ default:
+ if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.TChanDir() == types.Crecv {
+ mode.Fprintf(s, "chan (%v)", n.Left)
+ } else {
+ mode.Fprintf(s, "chan %v", n.Left)
+ }
+ }
+
+ case OTSTRUCT:
+ fmt.Fprint(s, "<struct>")
+
+ case OTINTER:
+ fmt.Fprint(s, "<inter>")
+
+ case OTFUNC:
+ fmt.Fprint(s, "<func>")
+
+ case OCLOSURE:
+ if mode == FErr {
+ fmt.Fprint(s, "func literal")
+ return
+ }
+ if n.Nbody.Len() != 0 {
+ mode.Fprintf(s, "%v { %v }", n.Type, n.Nbody)
+ return
+ }
+ mode.Fprintf(s, "%v { %v }", n.Type, n.Func.Closure.Nbody)
+
+ case OCOMPLIT:
+ if mode == FErr {
+ if n.Implicit() {
+ mode.Fprintf(s, "... argument")
+ return
+ }
+ if n.Right != nil {
+ mode.Fprintf(s, "%v{%s}", n.Right, ellipsisIf(n.List.Len() != 0))
+ return
+ }
+
+ fmt.Fprint(s, "composite literal")
+ return
+ }
+ mode.Fprintf(s, "(%v{ %.v })", n.Right, n.List)
+
+ case OPTRLIT:
+ mode.Fprintf(s, "&%v", n.Left)
+
+ case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
+ if mode == FErr {
+ mode.Fprintf(s, "%v{%s}", n.Type, ellipsisIf(n.List.Len() != 0))
+ return
+ }
+ mode.Fprintf(s, "(%v{ %.v })", n.Type, n.List)
+
+ case OKEY:
+ if n.Left != nil && n.Right != nil {
+ mode.Fprintf(s, "%v:%v", n.Left, n.Right)
+ return
+ }
+
+ if n.Left == nil && n.Right != nil {
+ mode.Fprintf(s, ":%v", n.Right)
+ return
+ }
+ if n.Left != nil && n.Right == nil {
+ mode.Fprintf(s, "%v:", n.Left)
+ return
+ }
+ fmt.Fprint(s, ":")
+
+ case OSTRUCTKEY:
+ mode.Fprintf(s, "%v:%v", n.Sym, n.Left)
+
+ case OCALLPART:
+ n.Left.exprfmt(s, nprec, mode)
+ if n.Right == nil || n.Right.Sym == nil {
+ fmt.Fprint(s, ".<nil>")
+ return
+ }
+ mode.Fprintf(s, ".%0S", n.Right.Sym)
+
+ case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+ n.Left.exprfmt(s, nprec, mode)
+ if n.Sym == nil {
+ fmt.Fprint(s, ".<nil>")
+ return
+ }
+ mode.Fprintf(s, ".%0S", n.Sym)
+
+ case ODOTTYPE, ODOTTYPE2:
+ n.Left.exprfmt(s, nprec, mode)
+ if n.Right != nil {
+ mode.Fprintf(s, ".(%v)", n.Right)
+ return
+ }
+ mode.Fprintf(s, ".(%v)", n.Type)
+
+ case OINDEX, OINDEXMAP:
+ n.Left.exprfmt(s, nprec, mode)
+ mode.Fprintf(s, "[%v]", n.Right)
+
+ case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
+ n.Left.exprfmt(s, nprec, mode)
+ fmt.Fprint(s, "[")
+ low, high, max := n.SliceBounds()
+ if low != nil {
+ fmt.Fprint(s, low.modeString(mode))
+ }
+ fmt.Fprint(s, ":")
+ if high != nil {
+ fmt.Fprint(s, high.modeString(mode))
+ }
+ if n.Op.IsSlice3() {
+ fmt.Fprint(s, ":")
+ if max != nil {
+ fmt.Fprint(s, max.modeString(mode))
+ }
+ }
+ fmt.Fprint(s, "]")
+
+ case OSLICEHEADER:
+ if n.List.Len() != 2 {
+ Fatalf("bad OSLICEHEADER list length %d", n.List.Len())
+ }
+ mode.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left, n.List.First(), n.List.Second())
+
+ case OCOMPLEX, OCOPY:
+ if n.Left != nil {
+ mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
+ } else {
+ mode.Fprintf(s, "%#v(%.v)", n.Op, n.List)
+ }
+
+ case OCONV,
+ OCONVIFACE,
+ OCONVNOP,
+ OBYTES2STR,
+ ORUNES2STR,
+ OSTR2BYTES,
+ OSTR2RUNES,
+ ORUNESTR:
+ if n.Type == nil || n.Type.Sym == nil {
+ mode.Fprintf(s, "(%v)", n.Type)
+ } else {
+ mode.Fprintf(s, "%v", n.Type)
+ }
+ if n.Left != nil {
+ mode.Fprintf(s, "(%v)", n.Left)
+ } else {
+ mode.Fprintf(s, "(%.v)", n.List)
+ }
+
+ case OREAL,
+ OIMAG,
+ OAPPEND,
+ OCAP,
+ OCLOSE,
+ ODELETE,
+ OLEN,
+ OMAKE,
+ ONEW,
+ OPANIC,
+ ORECOVER,
+ OALIGNOF,
+ OOFFSETOF,
+ OSIZEOF,
+ OPRINT,
+ OPRINTN:
+ if n.Left != nil {
+ mode.Fprintf(s, "%#v(%v)", n.Op, n.Left)
+ return
+ }
+ if n.IsDDD() {
+ mode.Fprintf(s, "%#v(%.v...)", n.Op, n.List)
+ return
+ }
+ mode.Fprintf(s, "%#v(%.v)", n.Op, n.List)
+
+ case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
+ n.Left.exprfmt(s, nprec, mode)
+ if n.IsDDD() {
+ mode.Fprintf(s, "(%.v...)", n.List)
+ return
+ }
+ mode.Fprintf(s, "(%.v)", n.List)
+
+ case OMAKEMAP, OMAKECHAN, OMAKESLICE:
+ if n.List.Len() != 0 { // pre-typecheck
+ mode.Fprintf(s, "make(%v, %.v)", n.Type, n.List)
+ return
+ }
+ if n.Right != nil {
+ mode.Fprintf(s, "make(%v, %v, %v)", n.Type, n.Left, n.Right)
+ return
+ }
+ if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) {
+ mode.Fprintf(s, "make(%v, %v)", n.Type, n.Left)
+ return
+ }
+ mode.Fprintf(s, "make(%v)", n.Type)
+
+ case OMAKESLICECOPY:
+ mode.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type, n.Left, n.Right)
+
+ case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
+ // Unary
+ mode.Fprintf(s, "%#v", n.Op)
+ if n.Left != nil && n.Left.Op == n.Op {
+ fmt.Fprint(s, " ")
+ }
+ n.Left.exprfmt(s, nprec+1, mode)
+
+ // Binary
+ case OADD,
+ OAND,
+ OANDAND,
+ OANDNOT,
+ ODIV,
+ OEQ,
+ OGE,
+ OGT,
+ OLE,
+ OLT,
+ OLSH,
+ OMOD,
+ OMUL,
+ ONE,
+ OOR,
+ OOROR,
+ ORSH,
+ OSEND,
+ OSUB,
+ OXOR:
+ n.Left.exprfmt(s, nprec, mode)
+ mode.Fprintf(s, " %#v ", n.Op)
+ n.Right.exprfmt(s, nprec+1, mode)
+
+ case OADDSTR:
+ for i, n1 := range n.List.Slice() {
+ if i != 0 {
+ fmt.Fprint(s, " + ")
+ }
+ n1.exprfmt(s, nprec, mode)
+ }
+ case ODDD:
+ mode.Fprintf(s, "...")
+ default:
+ mode.Fprintf(s, "<node %v>", n.Op)
+ }
+}
+
+func (n *Node) nodefmt(s fmt.State, flag FmtFlag, mode fmtMode) {
+ t := n.Type
+
+ // We almost always want the original.
+ // TODO(gri) Why the special case for OLITERAL?
+ if n.Op != OLITERAL && n.Orig != nil {
+ n = n.Orig
+ }
+
+ if flag&FmtLong != 0 && t != nil {
+ if t.Etype == TNIL {
+ fmt.Fprint(s, "nil")
+ } else if n.Op == ONAME && n.Name.AutoTemp() {
+ mode.Fprintf(s, "%v value", t)
+ } else {
+ mode.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 {
+ n.stmtfmt(s, mode)
+ return
+ }
+
+ n.exprfmt(s, 0, mode)
+}
+
+func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
+ recur := flag&FmtShort == 0
+
+ if recur {
+ indent(s)
+ if dumpdepth > 40 {
+ fmt.Fprint(s, "...")
+ return
+ }
+
+ if n.Ninit.Len() != 0 {
+ mode.Fprintf(s, "%v-init%v", n.Op, n.Ninit)
+ indent(s)
+ }
+ }
+
+ switch n.Op {
+ default:
+ mode.Fprintf(s, "%v%j", n.Op, n)
+
+ case OLITERAL:
+ mode.Fprintf(s, "%v-%v%j", n.Op, n.Val(), n)
+
+ case ONAME, ONONAME:
+ if n.Sym != nil {
+ mode.Fprintf(s, "%v-%v%j", n.Op, n.Sym, n)
+ } else {
+ mode.Fprintf(s, "%v%j", n.Op, n)
+ }
+ if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
+ indent(s)
+ mode.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
+ }
+
+ case OASOP:
+ mode.Fprintf(s, "%v-%v%j", n.Op, n.SubOp(), n)
+
+ case OTYPE:
+ mode.Fprintf(s, "%v %v%j type=%v", n.Op, n.Sym, n, n.Type)
+ if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
+ indent(s)
+ mode.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
+ }
+ }
+
+ if n.Op == OCLOSURE && n.Func.Closure != nil && n.Func.Closure.Func.Nname.Sym != nil {
+ mode.Fprintf(s, " fnName %v", n.Func.Closure.Func.Nname.Sym)
+ }
+ if n.Sym != nil && n.Op != ONAME {
+ mode.Fprintf(s, " %v", n.Sym)
+ }
+
+ if n.Type != nil {
+ mode.Fprintf(s, " %v", n.Type)
+ }
+
+ if recur {
+ if n.Left != nil {
+ mode.Fprintf(s, "%v", n.Left)
+ }
+ if n.Right != nil {
+ mode.Fprintf(s, "%v", n.Right)
+ }
+ if n.Func != nil && n.Func.Closure != nil && n.Func.Closure.Nbody.Len() != 0 {
+ indent(s)
+ // The function associated with a closure
+ mode.Fprintf(s, "%v-clofunc%v", n.Op, n.Func.Closure)
+ }
+ if n.Func != nil && n.Func.Dcl != nil && len(n.Func.Dcl) != 0 {
+ indent(s)
+ // The dcls for a func or closure
+ mode.Fprintf(s, "%v-dcl%v", n.Op, asNodes(n.Func.Dcl))
+ }
+ if n.List.Len() != 0 {
+ indent(s)
+ mode.Fprintf(s, "%v-list%v", n.Op, n.List)
+ }
+
+ if n.Rlist.Len() != 0 {
+ indent(s)
+ mode.Fprintf(s, "%v-rlist%v", n.Op, n.Rlist)
+ }
+
+ if n.Nbody.Len() != 0 {
+ indent(s)
+ mode.Fprintf(s, "%v-body%v", n.Op, n.Nbody)
+ }
+ }
+}
+
+// "%S" suppresses qualifying with package
+func symFormat(s *types.Sym, f fmt.State, verb rune, mode fmtMode) {
+ switch verb {
+ case 'v', 'S':
+ fmt.Fprint(f, sconv(s, fmtFlag(f, verb), mode))
+
+ default:
+ fmt.Fprintf(f, "%%!%c(*types.Sym=%p)", verb, s)
+ }
+}
+
+func smodeString(s *types.Sym, mode fmtMode) string { return sconv(s, 0, mode) }
+
+// See #16897 before changing the implementation of sconv.
+func sconv(s *types.Sym, flag FmtFlag, mode fmtMode) string {
+ if flag&FmtLong != 0 {
+ panic("linksymfmt")
+ }
+
+ if s == nil {
+ return "<S>"
+ }
+
+ if s.Name == "_" {
+ return "_"
+ }
+ buf := fmtBufferPool.Get().(*bytes.Buffer)
+ buf.Reset()
+ defer fmtBufferPool.Put(buf)
+
+ flag, mode = flag.update(mode)
+ symfmt(buf, s, flag, mode)
+ return types.InternString(buf.Bytes())
+}
+
+func sconv2(b *bytes.Buffer, s *types.Sym, flag FmtFlag, mode fmtMode) {
+ if flag&FmtLong != 0 {
+ panic("linksymfmt")
+ }
+ if s == nil {
+ b.WriteString("<S>")
+ return
+ }
+ if s.Name == "_" {
+ b.WriteString("_")
+ return
+ }
+
+ flag, mode = flag.update(mode)
+ symfmt(b, s, flag, mode)
+}
+
+func fldconv(b *bytes.Buffer, f *types.Field, flag FmtFlag, mode fmtMode, visited map[*types.Type]int, funarg types.Funarg) {
+ if f == nil {
+ b.WriteString("<T>")
+ return
+ }
+ flag, mode = flag.update(mode)
+ if mode == FTypeIdName {
+ flag |= FmtUnsigned
+ }
+
+ var name string
+ if flag&FmtShort == 0 {
+ s := f.Sym
+
+ // Take the name from the original.
+ if mode == FErr {
+ s = origSym(s)
+ }
+
+ if s != nil && f.Embedded == 0 {
+ if funarg != types.FunargNone {
+ name = asNode(f.Nname).modeString(mode)
+ } else if flag&FmtLong != 0 {
+ name = mode.Sprintf("%0S", s)
+ if !types.IsExported(name) && flag&FmtUnsigned == 0 {
+ name = smodeString(s, mode) // qualify non-exported names (used on structs, not on funarg)
+ }
+ } else {
+ name = smodeString(s, mode)
+ }
+ }
+ }
+
+ if name != "" {
+ b.WriteString(name)
+ b.WriteString(" ")
+ }
+
+ if f.IsDDD() {
+ var et *types.Type
+ if f.Type != nil {
+ et = f.Type.Elem()
+ }
+ b.WriteString("...")
+ tconv2(b, et, 0, mode, visited)
+ } else {
+ tconv2(b, f.Type, 0, mode, visited)
+ }
+
+ if flag&FmtShort == 0 && funarg == types.FunargNone && f.Note != "" {
+ b.WriteString(" ")
+ b.WriteString(strconv.Quote(f.Note))
+ }
+}
+
+// "%L" print definition, not name
+// "%S" omit 'func' and receiver from function types, short type names
+func typeFormat(t *types.Type, s fmt.State, verb rune, mode fmtMode) {
+ switch verb {
+ case 'v', 'S', 'L':
+ fmt.Fprint(s, tconv(t, fmtFlag(s, verb), mode))
+ default:
+ fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
+ }
+}
+
+func (n *Node) String() string { return fmt.Sprint(n) }
+func (n *Node) modeString(mode fmtMode) string { return mode.Sprint(n) }
+
+// "%L" suffix with "(type %T)" where possible
+// "%+S" in debug mode, don't recurse, no multiline output
+func (n *Node) nconv(s fmt.State, flag FmtFlag, mode fmtMode) {
+ if n == nil {
+ fmt.Fprint(s, "<N>")
+ return
+ }
+
+ flag, mode = flag.update(mode)
+
+ switch mode {
+ case FErr:
+ n.nodefmt(s, flag, mode)
+
+ case FDbg:
+ dumpdepth++
+ n.nodedump(s, flag, mode)
+ dumpdepth--
+
+ default:
+ Fatalf("unhandled %%N mode: %d", mode)
+ }
+}
+
+func (l Nodes) format(s fmt.State, verb rune, mode fmtMode) {
+ switch verb {
+ case 'v':
+ l.hconv(s, fmtFlag(s, verb), mode)
+
+ default:
+ fmt.Fprintf(s, "%%!%c(Nodes)", verb)
+ }
+}
+
+func (n Nodes) String() string {
+ return fmt.Sprint(n)
+}
+
+// Flags: all those of %N plus '.': separate with comma's instead of semicolons.
+func (l Nodes) hconv(s fmt.State, flag FmtFlag, mode fmtMode) {
+ if l.Len() == 0 && mode == FDbg {
+ fmt.Fprint(s, "<nil>")
+ return
+ }
+
+ flag, mode = flag.update(mode)
+ sep := "; "
+ if mode == FDbg {
+ sep = "\n"
+ } else if flag&FmtComma != 0 {
+ sep = ", "
+ }
+
+ for i, n := range l.Slice() {
+ fmt.Fprint(s, n.modeString(mode))
+ if i+1 < l.Len() {
+ fmt.Fprint(s, sep)
+ }
+ }
+}
+
+func dumplist(s string, l Nodes) {
+ fmt.Printf("%s%+v\n", s, l)
+}
+
+func fdumplist(w io.Writer, s string, l Nodes) {
+ fmt.Fprintf(w, "%s%+v\n", s, l)
+}
+
+func Dump(s string, n *Node) {
+ 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, ". ")
+ }
+}
+
+func ellipsisIf(b bool) string {
+ if b {
+ return "..."
+ }
+ return ""
+}
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
new file mode 100644
index 0000000..929653e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -0,0 +1,86 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+ "strconv"
+)
+
+// sysfunc looks up Go function name in package runtime. This function
+// must follow the internal calling convention.
+func sysfunc(name string) *obj.LSym {
+ s := Runtimepkg.Lookup(name)
+ s.SetFunc(true)
+ return s.Linksym()
+}
+
+// sysvar looks up a variable (or assembly function) name in package
+// runtime. If this is a function, it may have a special calling
+// convention.
+func sysvar(name string) *obj.LSym {
+ return Runtimepkg.Lookup(name).Linksym()
+}
+
+// isParamStackCopy reports whether this is the on-stack copy of a
+// function parameter that moved to the heap.
+func (n *Node) isParamStackCopy() bool {
+ return n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) && n.Name.Param.Heapaddr != nil
+}
+
+// isParamHeapCopy reports whether this is the on-heap copy of
+// a function parameter that moved to the heap.
+func (n *Node) isParamHeapCopy() bool {
+ return n.Op == ONAME && n.Class() == PAUTOHEAP && n.Name.Param.Stackcopy != nil
+}
+
+// autotmpname returns the name for an autotmp variable numbered n.
+func autotmpname(n int) string {
+ // Give each tmp a different name so that they can be registerized.
+ // Add a preceding . to avoid clashing with legal names.
+ const prefix = ".autotmp_"
+ // Start with a buffer big enough to hold a large n.
+ b := []byte(prefix + " ")[:len(prefix)]
+ b = strconv.AppendInt(b, int64(n), 10)
+ return types.InternString(b)
+}
+
+// make a new Node off the books
+func tempAt(pos src.XPos, curfn *Node, t *types.Type) *Node {
+ if curfn == nil {
+ Fatalf("no curfn for tempAt")
+ }
+ if curfn.Func.Closure != nil && curfn.Op == OCLOSURE {
+ Dump("tempAt", curfn)
+ Fatalf("adding tempAt to wrong closure function")
+ }
+ if t == nil {
+ Fatalf("tempAt called with nil type")
+ }
+
+ s := &types.Sym{
+ Name: autotmpname(len(curfn.Func.Dcl)),
+ Pkg: localpkg,
+ }
+ n := newnamel(pos, s)
+ s.Def = asTypesNode(n)
+ n.Type = t
+ n.SetClass(PAUTO)
+ n.Esc = EscNever
+ n.Name.Curfn = curfn
+ n.Name.SetUsed(true)
+ n.Name.SetAutoTemp(true)
+ curfn.Func.Dcl = append(curfn.Func.Dcl, n)
+
+ dowidth(t)
+
+ return n.Orig
+}
+
+func temp(t *types.Type) *Node {
+ return tempAt(lineno, Curfn, t)
+}
diff --git a/src/cmd/compile/internal/gc/global_test.go b/src/cmd/compile/internal/gc/global_test.go
new file mode 100644
index 0000000..edad6d0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/global_test.go
@@ -0,0 +1,116 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "bytes"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+// Make sure "hello world" does not link in all the
+// fmt.scanf routines. See issue 6853.
+func TestScanfRemoval(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ t.Parallel()
+
+ // Make a directory to work in.
+ dir, err := ioutil.TempDir("", "issue6853a-")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ // Create source.
+ src := filepath.Join(dir, "test.go")
+ f, err := os.Create(src)
+ if err != nil {
+ t.Fatalf("could not create source file: %v", err)
+ }
+ f.Write([]byte(`
+package main
+import "fmt"
+func main() {
+ fmt.Println("hello world")
+}
+`))
+ f.Close()
+
+ // Name of destination.
+ dst := filepath.Join(dir, "test")
+
+ // Compile source.
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", dst, src)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("could not build target: %v", err)
+ }
+
+ // Check destination to see if scanf code was included.
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "nm", dst)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("could not read target: %v", err)
+ }
+ if bytes.Contains(out, []byte("scanInt")) {
+ t.Fatalf("scanf code not removed from helloworld")
+ }
+}
+
+// Make sure -S prints assembly code. See issue 14515.
+func TestDashS(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ t.Parallel()
+
+ // Make a directory to work in.
+ dir, err := ioutil.TempDir("", "issue14515-")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ // Create source.
+ src := filepath.Join(dir, "test.go")
+ f, err := os.Create(src)
+ if err != nil {
+ t.Fatalf("could not create source file: %v", err)
+ }
+ f.Write([]byte(`
+package main
+import "fmt"
+func main() {
+ fmt.Println("hello world")
+}
+`))
+ f.Close()
+
+ // Compile source.
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags", "-S", "-o", filepath.Join(dir, "test"), src)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("could not build target: %v", err)
+ }
+
+ patterns := []string{
+ // It is hard to look for actual instructions in an
+ // arch-independent way. So we'll just look for
+ // pseudo-ops that are arch-independent.
+ "\tTEXT\t",
+ "\tFUNCDATA\t",
+ "\tPCDATA\t",
+ }
+ outstr := string(out)
+ for _, p := range patterns {
+ if !strings.Contains(outstr, p) {
+ println(outstr)
+ panic("can't find pattern " + p)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
new file mode 100644
index 0000000..274930b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/go.go
@@ -0,0 +1,349 @@
+// Copyright 2009 The Go Authors. 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"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+ "sync"
+)
+
+const (
+ BADWIDTH = types.BADWIDTH
+)
+
+var (
+ // maximum size variable which we will allocate on the stack.
+ // This limit is for explicit variable declarations like "var x T" or "x := ...".
+ // Note: the flag smallframes can update this value.
+ maxStackVarSize = int64(10 * 1024 * 1024)
+
+ // maximum size of implicit variables that we will allocate on the stack.
+ // p := new(T) allocating T on the stack
+ // p := &T{} allocating T on the stack
+ // s := make([]T, n) allocating [n]T on the stack
+ // s := []byte("...") allocating [n]byte on the stack
+ // Note: the flag smallframes can update this value.
+ maxImplicitStackVarSize = int64(64 * 1024)
+
+ // smallArrayBytes is the maximum size of an array which is considered small.
+ // Small arrays will be initialized directly with a sequence of constant stores.
+ // Large arrays will be initialized by copying from a static temp.
+ // 256 bytes was chosen to minimize generated code + statictmp size.
+ smallArrayBytes = int64(256)
+)
+
+// isRuntimePkg reports whether p is package runtime.
+func isRuntimePkg(p *types.Pkg) bool {
+ if compiling_runtime && p == localpkg {
+ return true
+ }
+ return p.Path == "runtime"
+}
+
+// isReflectPkg reports whether p is package reflect.
+func isReflectPkg(p *types.Pkg) bool {
+ if p == localpkg {
+ return myimportpath == "reflect"
+ }
+ return p.Path == "reflect"
+}
+
+// The Class of a variable/function describes the "storage class"
+// of a variable or function. During parsing, storage classes are
+// called declaration contexts.
+type Class uint8
+
+//go:generate stringer -type=Class
+const (
+ Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
+ PEXTERN // global variables
+ PAUTO // local variables
+ PAUTOHEAP // local variables or parameters moved to heap
+ PPARAM // input arguments
+ PPARAMOUT // output results
+ PFUNC // global functions
+
+ // Careful: Class is stored in three bits in Node.flags.
+ _ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
+)
+
+// Slices in the runtime are represented by three components:
+//
+// type slice struct {
+// ptr unsafe.Pointer
+// len int
+// cap int
+// }
+//
+// Strings in the runtime are represented by two components:
+//
+// type string struct {
+// ptr unsafe.Pointer
+// len int
+// }
+//
+// These variables are the offsets of fields and sizes of these structs.
+var (
+ slicePtrOffset int64
+ sliceLenOffset int64
+ sliceCapOffset int64
+
+ sizeofSlice int64
+ sizeofString int64
+)
+
+var pragcgobuf [][]string
+
+var outfile string
+var linkobj string
+
+// 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
+
+var decldepth int32
+
+var nolocalimports bool
+
+// gc debug flags
+type DebugFlags struct {
+ P, B, C, E,
+ K, L, N, S,
+ W, e, h, j,
+ l, m, r, w int
+}
+
+var Debug DebugFlags
+
+var debugstr string
+
+var Debug_checknil int
+var Debug_typeassert int
+
+var localpkg *types.Pkg // package being compiled
+
+var inimport bool // set during import
+
+var itabpkg *types.Pkg // fake pkg for itab entries
+
+var itablinkpkg *types.Pkg // fake package for runtime itab entries
+
+var Runtimepkg *types.Pkg // fake package runtime
+
+var racepkg *types.Pkg // package runtime/race
+
+var msanpkg *types.Pkg // package runtime/msan
+
+var unsafepkg *types.Pkg // package unsafe
+
+var trackpkg *types.Pkg // fake package for field tracking
+
+var mappkg *types.Pkg // fake package for map zero value
+
+var gopkg *types.Pkg // pseudo-package for method symbols on anonymous receiver types
+
+var zerosize int64
+
+var myimportpath string
+
+var localimport string
+
+var asmhdr string
+
+var simtype [NTYPE]types.EType
+
+var (
+ isInt [NTYPE]bool
+ isFloat [NTYPE]bool
+ isComplex [NTYPE]bool
+ issimple [NTYPE]bool
+)
+
+var (
+ okforeq [NTYPE]bool
+ okforadd [NTYPE]bool
+ okforand [NTYPE]bool
+ okfornone [NTYPE]bool
+ okforcmp [NTYPE]bool
+ okforbool [NTYPE]bool
+ okforcap [NTYPE]bool
+ okforlen [NTYPE]bool
+ okforarith [NTYPE]bool
+ okforconst [NTYPE]bool
+)
+
+var (
+ okfor [OEND][]bool
+ iscmp [OEND]bool
+)
+
+var minintval [NTYPE]*Mpint
+
+var maxintval [NTYPE]*Mpint
+
+var minfltval [NTYPE]*Mpflt
+
+var maxfltval [NTYPE]*Mpflt
+
+var xtop []*Node
+
+var exportlist []*Node
+
+var importlist []*Node // imported functions and methods with inlinable bodies
+
+var (
+ funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
+ funcsyms []*types.Sym
+)
+
+var dclcontext Class // PEXTERN/PAUTO
+
+var Curfn *Node
+
+var Widthptr int
+
+var Widthreg int
+
+var nblank *Node
+
+var typecheckok bool
+
+var compiling_runtime bool
+
+// Compiling the standard library
+var compiling_std bool
+
+var use_writebarrier bool
+
+var pure_go bool
+
+var flag_installsuffix string
+
+var flag_race bool
+
+var flag_msan bool
+
+var flagDWARF bool
+
+// Whether we are adding any sort of code instrumentation, such as
+// when the race detector is enabled.
+var instrumenting bool
+
+// Whether we are tracking lexical scopes for DWARF.
+var trackScopes bool
+
+// Controls generation of DWARF inlined instance records. Zero
+// disables, 1 emits inlined routines but suppresses var info,
+// and 2 emits inlined routines with tracking of formals/locals.
+var genDwarfInline int
+
+var debuglive int
+
+var Ctxt *obj.Link
+
+var writearchive bool
+
+var nodfp *Node
+
+var disable_checknil int
+
+var autogeneratedPos src.XPos
+
+// interface to back end
+
+type Arch struct {
+ LinkArch *obj.LinkArch
+
+ REGSP int
+ MAXWIDTH int64
+ SoftFloat bool
+
+ PadFrame func(int64) int64
+
+ // ZeroRange zeroes a range of memory on stack. It is only inserted
+ // at function entry, and it is ok to clobber registers.
+ ZeroRange func(*Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog
+
+ Ginsnop func(*Progs) *obj.Prog
+ Ginsnopdefer func(*Progs) *obj.Prog // special ginsnop for deferreturn
+
+ // SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
+ SSAMarkMoves func(*SSAGenState, *ssa.Block)
+
+ // SSAGenValue emits Prog(s) for the Value.
+ SSAGenValue func(*SSAGenState, *ssa.Value)
+
+ // SSAGenBlock emits end-of-block Progs. SSAGenValue should be called
+ // for all values in the block before SSAGenBlock.
+ SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
+}
+
+var thearch Arch
+
+var (
+ staticuint64s,
+ zerobase *Node
+
+ assertE2I,
+ assertE2I2,
+ assertI2I,
+ assertI2I2,
+ deferproc,
+ deferprocStack,
+ Deferreturn,
+ Duffcopy,
+ Duffzero,
+ gcWriteBarrier,
+ goschedguarded,
+ growslice,
+ msanread,
+ msanwrite,
+ msanmove,
+ newobject,
+ newproc,
+ panicdivide,
+ panicshift,
+ panicdottypeE,
+ panicdottypeI,
+ panicnildottype,
+ panicoverflow,
+ raceread,
+ racereadrange,
+ racewrite,
+ racewriterange,
+ x86HasPOPCNT,
+ x86HasSSE41,
+ x86HasFMA,
+ armHasVFPv4,
+ arm64HasATOMICS,
+ typedmemclr,
+ typedmemmove,
+ Udiv,
+ writeBarrier,
+ zerobaseSym *obj.LSym
+
+ BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
+ ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym
+
+ // Wasm
+ WasmMove,
+ WasmZero,
+ WasmDiv,
+ WasmTruncS,
+ WasmTruncU,
+ SigPanic *obj.LSym
+)
+
+// GCWriteBarrierReg maps from registers to gcWriteBarrier implementation LSyms.
+var GCWriteBarrierReg map[int16]*obj.LSym
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
new file mode 100644
index 0000000..d599a38
--- /dev/null
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -0,0 +1,333 @@
+// Derived from Inferno utils/6c/txt.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package gc
+
+import (
+ "cmd/compile/internal/ssa"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+)
+
+var sharedProgArray = new([10000]obj.Prog) // *T instead of T to work around issue 19839
+
+// Progs accumulates Progs for a function and converts them into machine code.
+type Progs struct {
+ Text *obj.Prog // ATEXT Prog for this function
+ next *obj.Prog // next Prog
+ pc int64 // virtual PC; count of Progs
+ pos src.XPos // position to use for new Progs
+ curfn *Node // fn these Progs are for
+ progcache []obj.Prog // local progcache
+ cacheidx int // first free element of progcache
+
+ nextLive LivenessIndex // liveness index for the next Prog
+ prevLive LivenessIndex // last emitted liveness index
+}
+
+// newProgs returns a new Progs for fn.
+// worker indicates which of the backend workers will use the Progs.
+func newProgs(fn *Node, worker int) *Progs {
+ pp := new(Progs)
+ if Ctxt.CanReuseProgs() {
+ sz := len(sharedProgArray) / nBackendWorkers
+ pp.progcache = sharedProgArray[sz*worker : sz*(worker+1)]
+ }
+ pp.curfn = fn
+
+ // prime the pump
+ pp.next = pp.NewProg()
+ pp.clearp(pp.next)
+
+ pp.pos = fn.Pos
+ pp.settext(fn)
+ // PCDATA tables implicitly start with index -1.
+ pp.prevLive = LivenessIndex{-1, false}
+ pp.nextLive = pp.prevLive
+ return pp
+}
+
+func (pp *Progs) NewProg() *obj.Prog {
+ var p *obj.Prog
+ if pp.cacheidx < len(pp.progcache) {
+ p = &pp.progcache[pp.cacheidx]
+ pp.cacheidx++
+ } else {
+ p = new(obj.Prog)
+ }
+ p.Ctxt = Ctxt
+ return p
+}
+
+// Flush converts from pp to machine code.
+func (pp *Progs) Flush() {
+ plist := &obj.Plist{Firstpc: pp.Text, Curfn: pp.curfn}
+ obj.Flushplist(Ctxt, plist, pp.NewProg, myimportpath)
+}
+
+// Free clears pp and any associated resources.
+func (pp *Progs) Free() {
+ if Ctxt.CanReuseProgs() {
+ // Clear progs to enable GC and avoid abuse.
+ s := pp.progcache[:pp.cacheidx]
+ for i := range s {
+ s[i] = obj.Prog{}
+ }
+ }
+ // Clear pp to avoid abuse.
+ *pp = Progs{}
+}
+
+// Prog adds a Prog with instruction As to pp.
+func (pp *Progs) Prog(as obj.As) *obj.Prog {
+ if pp.nextLive.StackMapValid() && pp.nextLive.stackMapIndex != pp.prevLive.stackMapIndex {
+ // Emit stack map index change.
+ idx := pp.nextLive.stackMapIndex
+ pp.prevLive.stackMapIndex = idx
+ p := pp.Prog(obj.APCDATA)
+ Addrconst(&p.From, objabi.PCDATA_StackMapIndex)
+ Addrconst(&p.To, int64(idx))
+ }
+ if pp.nextLive.isUnsafePoint != pp.prevLive.isUnsafePoint {
+ // Emit unsafe-point marker.
+ pp.prevLive.isUnsafePoint = pp.nextLive.isUnsafePoint
+ p := pp.Prog(obj.APCDATA)
+ Addrconst(&p.From, objabi.PCDATA_UnsafePoint)
+ if pp.nextLive.isUnsafePoint {
+ Addrconst(&p.To, objabi.PCDATA_UnsafePointUnsafe)
+ } else {
+ Addrconst(&p.To, objabi.PCDATA_UnsafePointSafe)
+ }
+ }
+
+ p := pp.next
+ pp.next = pp.NewProg()
+ pp.clearp(pp.next)
+ p.Link = pp.next
+
+ if !pp.pos.IsKnown() && Debug.K != 0 {
+ Warn("prog: unknown position (line 0)")
+ }
+
+ p.As = as
+ p.Pos = pp.pos
+ if pp.pos.IsStmt() == src.PosIsStmt {
+ // Clear IsStmt for later Progs at this pos provided that as can be marked as a stmt
+ if ssa.LosesStmtMark(as) {
+ return p
+ }
+ pp.pos = pp.pos.WithNotStmt()
+ }
+ return p
+}
+
+func (pp *Progs) clearp(p *obj.Prog) {
+ obj.Nopout(p)
+ p.As = obj.AEND
+ p.Pc = pp.pc
+ pp.pc++
+}
+
+func (pp *Progs) Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset int64, ttype obj.AddrType, treg int16, toffset int64) *obj.Prog {
+ q := pp.NewProg()
+ pp.clearp(q)
+ q.As = as
+ q.Pos = p.Pos
+ 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 (pp *Progs) settext(fn *Node) {
+ if pp.Text != nil {
+ Fatalf("Progs.settext called twice")
+ }
+ ptxt := pp.Prog(obj.ATEXT)
+ pp.Text = ptxt
+
+ fn.Func.lsym.Func().Text = ptxt
+ ptxt.From.Type = obj.TYPE_MEM
+ ptxt.From.Name = obj.NAME_EXTERN
+ ptxt.From.Sym = fn.Func.lsym
+}
+
+// initLSym defines f's obj.LSym and initializes it based on the
+// properties of f. This includes setting the symbol flags and ABI and
+// creating and initializing related DWARF symbols.
+//
+// initLSym must be called exactly once per function and must be
+// called for both functions with bodies and functions without bodies.
+func (f *Func) initLSym(hasBody bool) {
+ if f.lsym != nil {
+ Fatalf("Func.initLSym called twice")
+ }
+
+ if nam := f.Nname; !nam.isBlank() {
+ f.lsym = nam.Sym.Linksym()
+ if f.Pragma&Systemstack != 0 {
+ f.lsym.Set(obj.AttrCFunc, true)
+ }
+
+ var aliasABI obj.ABI
+ needABIAlias := false
+ defABI, hasDefABI := symabiDefs[f.lsym.Name]
+ if hasDefABI && defABI == obj.ABI0 {
+ // Symbol is defined as ABI0. Create an
+ // Internal -> ABI0 wrapper.
+ f.lsym.SetABI(obj.ABI0)
+ needABIAlias, aliasABI = true, obj.ABIInternal
+ } else {
+ // No ABI override. Check that the symbol is
+ // using the expected ABI.
+ want := obj.ABIInternal
+ if f.lsym.ABI() != want {
+ Fatalf("function symbol %s has the wrong ABI %v, expected %v", f.lsym.Name, f.lsym.ABI(), want)
+ }
+ }
+
+ isLinknameExported := nam.Sym.Linkname != "" && (hasBody || hasDefABI)
+ if abi, ok := symabiRefs[f.lsym.Name]; (ok && abi == obj.ABI0) || isLinknameExported {
+ // Either 1) this symbol is definitely
+ // referenced as ABI0 from this package; or 2)
+ // this symbol is defined in this package but
+ // given a linkname, indicating that it may be
+ // referenced from another package. Create an
+ // ABI0 -> Internal wrapper so it can be
+ // called as ABI0. In case 2, it's important
+ // that we know it's defined in this package
+ // since other packages may "pull" symbols
+ // using linkname and we don't want to create
+ // duplicate ABI wrappers.
+ if f.lsym.ABI() != obj.ABI0 {
+ needABIAlias, aliasABI = true, obj.ABI0
+ }
+ }
+
+ if needABIAlias {
+ // These LSyms have the same name as the
+ // native function, so we create them directly
+ // rather than looking them up. The uniqueness
+ // of f.lsym ensures uniqueness of asym.
+ asym := &obj.LSym{
+ Name: f.lsym.Name,
+ Type: objabi.SABIALIAS,
+ R: []obj.Reloc{{Sym: f.lsym}}, // 0 size, so "informational"
+ }
+ asym.SetABI(aliasABI)
+ asym.Set(obj.AttrDuplicateOK, true)
+ Ctxt.ABIAliases = append(Ctxt.ABIAliases, asym)
+ }
+ }
+
+ if !hasBody {
+ // For body-less functions, we only create the LSym.
+ return
+ }
+
+ var flag int
+ if f.Dupok() {
+ flag |= obj.DUPOK
+ }
+ if f.Wrapper() {
+ flag |= obj.WRAPPER
+ }
+ if f.Needctxt() {
+ flag |= obj.NEEDCTXT
+ }
+ if f.Pragma&Nosplit != 0 {
+ flag |= obj.NOSPLIT
+ }
+ if f.ReflectMethod() {
+ flag |= obj.REFLECTMETHOD
+ }
+
+ // Clumsy but important.
+ // See test/recover.go for test cases and src/reflect/value.go
+ // for the actual functions being considered.
+ if myimportpath == "reflect" {
+ switch f.Nname.Sym.Name {
+ case "callReflect", "callMethod":
+ flag |= obj.WRAPPER
+ }
+ }
+
+ Ctxt.InitTextSym(f.lsym, flag)
+}
+
+func ggloblnod(nam *Node) {
+ s := nam.Sym.Linksym()
+ s.Gotype = ngotype(nam).Linksym()
+ flags := 0
+ if nam.Name.Readonly() {
+ flags = obj.RODATA
+ }
+ if nam.Type != nil && !nam.Type.HasPointers() {
+ flags |= obj.NOPTR
+ }
+ Ctxt.Globl(s, nam.Type.Width, flags)
+ if nam.Name.LibfuzzerExtraCounter() {
+ s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
+ }
+ if nam.Sym.Linkname != "" {
+ // Make sure linkname'd symbol is non-package. When a symbol is
+ // both imported and linkname'd, s.Pkg may not set to "_" in
+ // types.Sym.Linksym because LSym already exists. Set it here.
+ s.Pkg = "_"
+ }
+}
+
+func ggloblsym(s *obj.LSym, width int32, flags int16) {
+ if flags&obj.LOCAL != 0 {
+ s.Set(obj.AttrLocal, true)
+ flags &^= obj.LOCAL
+ }
+ Ctxt.Globl(s, int64(width), int(flags))
+}
+
+func Addrconst(a *obj.Addr, v int64) {
+ a.Sym = nil
+ a.Type = obj.TYPE_CONST
+ a.Offset = v
+}
+
+func Patch(p *obj.Prog, to *obj.Prog) {
+ if p.To.Type != obj.TYPE_BRANCH {
+ Fatalf("patch: not a branch")
+ }
+ p.To.SetTarget(to)
+ p.To.Offset = to.Pc
+}
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
new file mode 100644
index 0000000..1f53d8c
--- /dev/null
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -0,0 +1,1515 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Indexed package export.
+//
+// The indexed export data format is an evolution of the previous
+// binary export data format. Its chief contribution is introducing an
+// index table, which allows efficient random access of individual
+// declarations and inline function bodies. In turn, this allows
+// avoiding unnecessary work for compilation units that import large
+// packages.
+//
+//
+// The top-level data format is structured as:
+//
+// Header struct {
+// Tag byte // 'i'
+// Version uvarint
+// StringSize uvarint
+// DataSize uvarint
+// }
+//
+// Strings [StringSize]byte
+// Data [DataSize]byte
+//
+// MainIndex []struct{
+// PkgPath stringOff
+// PkgName stringOff
+// PkgHeight uvarint
+//
+// Decls []struct{
+// Name stringOff
+// Offset declOff
+// }
+// }
+//
+// Fingerprint [8]byte
+//
+// uvarint means a uint64 written out using uvarint encoding.
+//
+// []T means a uvarint followed by that many T objects. In other
+// words:
+//
+// Len uvarint
+// Elems [Len]T
+//
+// stringOff means a uvarint that indicates an offset within the
+// Strings section. At that offset is another uvarint, followed by
+// that many bytes, which form the string value.
+//
+// declOff means a uvarint that indicates an offset within the Data
+// section where the associated declaration can be found.
+//
+//
+// There are five kinds of declarations, distinguished by their first
+// byte:
+//
+// type Var struct {
+// Tag byte // 'V'
+// Pos Pos
+// Type typeOff
+// }
+//
+// type Func struct {
+// Tag byte // 'F'
+// Pos Pos
+// Signature Signature
+// }
+//
+// type Const struct {
+// Tag byte // 'C'
+// Pos Pos
+// Value Value
+// }
+//
+// type Type struct {
+// Tag byte // 'T'
+// Pos Pos
+// Underlying typeOff
+//
+// Methods []struct{ // omitted if Underlying is an interface type
+// Pos Pos
+// Name stringOff
+// Recv Param
+// Signature Signature
+// }
+// }
+//
+// type Alias struct {
+// Tag byte // 'A'
+// Pos Pos
+// Type typeOff
+// }
+//
+//
+// typeOff means a uvarint that either indicates a predeclared type,
+// or an offset into the Data section. If the uvarint is less than
+// predeclReserved, then it indicates the index into the predeclared
+// types list (see predeclared in bexport.go for order). Otherwise,
+// subtracting predeclReserved yields the offset of a type descriptor.
+//
+// Value means a type and type-specific value. See
+// (*exportWriter).value for details.
+//
+//
+// There are nine kinds of type descriptors, distinguished by an itag:
+//
+// type DefinedType struct {
+// Tag itag // definedType
+// Name stringOff
+// PkgPath stringOff
+// }
+//
+// type PointerType struct {
+// Tag itag // pointerType
+// Elem typeOff
+// }
+//
+// type SliceType struct {
+// Tag itag // sliceType
+// Elem typeOff
+// }
+//
+// type ArrayType struct {
+// Tag itag // arrayType
+// Len uint64
+// Elem typeOff
+// }
+//
+// type ChanType struct {
+// Tag itag // chanType
+// Dir uint64 // 1 RecvOnly; 2 SendOnly; 3 SendRecv
+// Elem typeOff
+// }
+//
+// type MapType struct {
+// Tag itag // mapType
+// Key typeOff
+// Elem typeOff
+// }
+//
+// type FuncType struct {
+// Tag itag // signatureType
+// PkgPath stringOff
+// Signature Signature
+// }
+//
+// type StructType struct {
+// Tag itag // structType
+// PkgPath stringOff
+// Fields []struct {
+// Pos Pos
+// Name stringOff
+// Type typeOff
+// Embedded bool
+// Note stringOff
+// }
+// }
+//
+// type InterfaceType struct {
+// Tag itag // interfaceType
+// PkgPath stringOff
+// Embeddeds []struct {
+// Pos Pos
+// Type typeOff
+// }
+// Methods []struct {
+// Pos Pos
+// Name stringOff
+// Signature Signature
+// }
+// }
+//
+//
+// type Signature struct {
+// Params []Param
+// Results []Param
+// Variadic bool // omitted if Results is empty
+// }
+//
+// type Param struct {
+// Pos Pos
+// Name stringOff
+// Type typOff
+// }
+//
+//
+// Pos encodes a file:line:column triple, incorporating a simple delta
+// encoding scheme within a data object. See exportWriter.pos for
+// details.
+//
+//
+// Compiler-specific details.
+//
+// cmd/compile writes out a second index for inline bodies and also
+// appends additional compiler-specific details after declarations.
+// Third-party tools are not expected to depend on these details and
+// they're expected to change much more rapidly, so they're omitted
+// here. See exportWriter's varExt/funcExt/etc methods for details.
+
+package gc
+
+import (
+ "bufio"
+ "bytes"
+ "cmd/compile/internal/types"
+ "cmd/internal/goobj"
+ "cmd/internal/src"
+ "crypto/md5"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "math/big"
+ "sort"
+ "strings"
+)
+
+// Current indexed export format version. Increase with each format change.
+// 1: added column details to Pos
+// 0: Go1.11 encoding
+const iexportVersion = 1
+
+// predeclReserved is the number of type offsets reserved for types
+// implicitly declared in the universe block.
+const predeclReserved = 32
+
+// An itag distinguishes the kind of type that was written into the
+// indexed export format.
+type itag uint64
+
+const (
+ // Types
+ definedType itag = iota
+ pointerType
+ sliceType
+ arrayType
+ chanType
+ mapType
+ signatureType
+ structType
+ interfaceType
+)
+
+func iexport(out *bufio.Writer) {
+ // Mark inline bodies that are reachable through exported types.
+ // (Phase 0 of bexport.go.)
+ {
+ // TODO(mdempsky): Separate from bexport logic.
+ p := &exporter{marked: make(map[*types.Type]bool)}
+ for _, n := range exportlist {
+ sym := n.Sym
+ p.markType(asNode(sym.Def).Type)
+ }
+ }
+
+ p := iexporter{
+ allPkgs: map[*types.Pkg]bool{},
+ stringIndex: map[string]uint64{},
+ declIndex: map[*Node]uint64{},
+ inlineIndex: map[*Node]uint64{},
+ typIndex: map[*types.Type]uint64{},
+ }
+
+ for i, pt := range predeclared() {
+ p.typIndex[pt] = uint64(i)
+ }
+ if len(p.typIndex) > predeclReserved {
+ Fatalf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved)
+ }
+
+ // Initialize work queue with exported declarations.
+ for _, n := range exportlist {
+ p.pushDecl(n)
+ }
+
+ // Loop until no more work. We use a queue because while
+ // writing out inline bodies, we may discover additional
+ // declarations that are needed.
+ for !p.declTodo.empty() {
+ p.doDecl(p.declTodo.popLeft())
+ }
+
+ // Append indices to data0 section.
+ dataLen := uint64(p.data0.Len())
+ w := p.newWriter()
+ w.writeIndex(p.declIndex, true)
+ w.writeIndex(p.inlineIndex, false)
+ w.flush()
+
+ // Assemble header.
+ var hdr intWriter
+ hdr.WriteByte('i')
+ hdr.uint64(iexportVersion)
+ hdr.uint64(uint64(p.strings.Len()))
+ hdr.uint64(dataLen)
+
+ // Flush output.
+ h := md5.New()
+ wr := io.MultiWriter(out, h)
+ io.Copy(wr, &hdr)
+ io.Copy(wr, &p.strings)
+ io.Copy(wr, &p.data0)
+
+ // Add fingerprint (used by linker object file).
+ // Attach this to the end, so tools (e.g. gcimporter) don't care.
+ copy(Ctxt.Fingerprint[:], h.Sum(nil)[:])
+ out.Write(Ctxt.Fingerprint[:])
+}
+
+// writeIndex writes out an object index. mainIndex indicates whether
+// we're writing out the main index, which is also read by
+// non-compiler tools and includes a complete package description
+// (i.e., name and height).
+func (w *exportWriter) writeIndex(index map[*Node]uint64, mainIndex bool) {
+ // Build a map from packages to objects from that package.
+ pkgObjs := map[*types.Pkg][]*Node{}
+
+ // For the main index, make sure to include every package that
+ // we reference, even if we're not exporting (or reexporting)
+ // any symbols from it.
+ if mainIndex {
+ pkgObjs[localpkg] = nil
+ for pkg := range w.p.allPkgs {
+ pkgObjs[pkg] = nil
+ }
+ }
+
+ for n := range index {
+ pkgObjs[n.Sym.Pkg] = append(pkgObjs[n.Sym.Pkg], n)
+ }
+
+ var pkgs []*types.Pkg
+ for pkg, objs := range pkgObjs {
+ pkgs = append(pkgs, pkg)
+
+ sort.Slice(objs, func(i, j int) bool {
+ return objs[i].Sym.Name < objs[j].Sym.Name
+ })
+ }
+
+ sort.Slice(pkgs, func(i, j int) bool {
+ return pkgs[i].Path < pkgs[j].Path
+ })
+
+ w.uint64(uint64(len(pkgs)))
+ for _, pkg := range pkgs {
+ w.string(pkg.Path)
+ if mainIndex {
+ w.string(pkg.Name)
+ w.uint64(uint64(pkg.Height))
+ }
+
+ objs := pkgObjs[pkg]
+ w.uint64(uint64(len(objs)))
+ for _, n := range objs {
+ w.string(n.Sym.Name)
+ w.uint64(index[n])
+ }
+ }
+}
+
+type iexporter struct {
+ // allPkgs tracks all packages that have been referenced by
+ // the export data, so we can ensure to include them in the
+ // main index.
+ allPkgs map[*types.Pkg]bool
+
+ declTodo nodeQueue
+
+ strings intWriter
+ stringIndex map[string]uint64
+
+ data0 intWriter
+ declIndex map[*Node]uint64
+ inlineIndex map[*Node]uint64
+ typIndex map[*types.Type]uint64
+}
+
+// stringOff returns the offset of s within the string section.
+// If not already present, it's added to the end.
+func (p *iexporter) stringOff(s string) uint64 {
+ off, ok := p.stringIndex[s]
+ if !ok {
+ off = uint64(p.strings.Len())
+ p.stringIndex[s] = off
+
+ p.strings.uint64(uint64(len(s)))
+ p.strings.WriteString(s)
+ }
+ return off
+}
+
+// pushDecl adds n to the declaration work queue, if not already present.
+func (p *iexporter) pushDecl(n *Node) {
+ if n.Sym == nil || asNode(n.Sym.Def) != n && n.Op != OTYPE {
+ Fatalf("weird Sym: %v, %v", n, n.Sym)
+ }
+
+ // Don't export predeclared declarations.
+ if n.Sym.Pkg == builtinpkg || n.Sym.Pkg == unsafepkg {
+ return
+ }
+
+ if _, ok := p.declIndex[n]; ok {
+ return
+ }
+
+ p.declIndex[n] = ^uint64(0) // mark n present in work queue
+ p.declTodo.pushRight(n)
+}
+
+// exportWriter handles writing out individual data section chunks.
+type exportWriter struct {
+ p *iexporter
+
+ data intWriter
+ currPkg *types.Pkg
+ prevFile string
+ prevLine int64
+ prevColumn int64
+}
+
+func (p *iexporter) doDecl(n *Node) {
+ w := p.newWriter()
+ w.setPkg(n.Sym.Pkg, false)
+
+ switch n.Op {
+ case ONAME:
+ switch n.Class() {
+ case PEXTERN:
+ // Variable.
+ w.tag('V')
+ w.pos(n.Pos)
+ w.typ(n.Type)
+ w.varExt(n)
+
+ case PFUNC:
+ if n.IsMethod() {
+ Fatalf("unexpected method: %v", n)
+ }
+
+ // Function.
+ w.tag('F')
+ w.pos(n.Pos)
+ w.signature(n.Type)
+ w.funcExt(n)
+
+ default:
+ Fatalf("unexpected class: %v, %v", n, n.Class())
+ }
+
+ case OLITERAL:
+ // Constant.
+ n = typecheck(n, ctxExpr)
+ w.tag('C')
+ w.pos(n.Pos)
+ w.value(n.Type, n.Val())
+
+ case OTYPE:
+ if IsAlias(n.Sym) {
+ // Alias.
+ w.tag('A')
+ w.pos(n.Pos)
+ w.typ(n.Type)
+ break
+ }
+
+ // Defined type.
+ w.tag('T')
+ w.pos(n.Pos)
+
+ underlying := n.Type.Orig
+ if underlying == types.Errortype.Orig {
+ // For "type T error", use error as the
+ // underlying type instead of error's own
+ // underlying anonymous interface. This
+ // ensures consistency with how importers may
+ // declare error (e.g., go/types uses nil Pkg
+ // for predeclared objects).
+ underlying = types.Errortype
+ }
+ w.typ(underlying)
+
+ t := n.Type
+ if t.IsInterface() {
+ w.typeExt(t)
+ break
+ }
+
+ ms := t.Methods()
+ w.uint64(uint64(ms.Len()))
+ for _, m := range ms.Slice() {
+ w.pos(m.Pos)
+ w.selector(m.Sym)
+ w.param(m.Type.Recv())
+ w.signature(m.Type)
+ }
+
+ w.typeExt(t)
+ for _, m := range ms.Slice() {
+ w.methExt(m)
+ }
+
+ default:
+ Fatalf("unexpected node: %v", n)
+ }
+
+ p.declIndex[n] = w.flush()
+}
+
+func (w *exportWriter) tag(tag byte) {
+ w.data.WriteByte(tag)
+}
+
+func (p *iexporter) doInline(f *Node) {
+ w := p.newWriter()
+ w.setPkg(fnpkg(f), false)
+
+ w.stmtList(asNodes(f.Func.Inl.Body))
+
+ p.inlineIndex[f] = w.flush()
+}
+
+func (w *exportWriter) pos(pos src.XPos) {
+ p := Ctxt.PosTable.Pos(pos)
+ file := p.Base().AbsFilename()
+ line := int64(p.RelLine())
+ column := int64(p.RelCol())
+
+ // Encode position relative to the last position: column
+ // delta, then line delta, then file name. We reserve the
+ // bottom bit of the column and line deltas to encode whether
+ // the remaining fields are present.
+ //
+ // Note: Because data objects may be read out of order (or not
+ // at all), we can only apply delta encoding within a single
+ // object. This is handled implicitly by tracking prevFile,
+ // prevLine, and prevColumn as fields of exportWriter.
+
+ deltaColumn := (column - w.prevColumn) << 1
+ deltaLine := (line - w.prevLine) << 1
+
+ if file != w.prevFile {
+ deltaLine |= 1
+ }
+ if deltaLine != 0 {
+ deltaColumn |= 1
+ }
+
+ w.int64(deltaColumn)
+ if deltaColumn&1 != 0 {
+ w.int64(deltaLine)
+ if deltaLine&1 != 0 {
+ w.string(file)
+ }
+ }
+
+ w.prevFile = file
+ w.prevLine = line
+ w.prevColumn = column
+}
+
+func (w *exportWriter) pkg(pkg *types.Pkg) {
+ // Ensure any referenced packages are declared in the main index.
+ w.p.allPkgs[pkg] = true
+
+ w.string(pkg.Path)
+}
+
+func (w *exportWriter) qualifiedIdent(n *Node) {
+ // Ensure any referenced declarations are written out too.
+ w.p.pushDecl(n)
+
+ s := n.Sym
+ w.string(s.Name)
+ w.pkg(s.Pkg)
+}
+
+func (w *exportWriter) selector(s *types.Sym) {
+ if w.currPkg == nil {
+ Fatalf("missing currPkg")
+ }
+
+ // Method selectors are rewritten into method symbols (of the
+ // form T.M) during typechecking, but we want to write out
+ // just the bare method name.
+ name := s.Name
+ if i := strings.LastIndex(name, "."); i >= 0 {
+ name = name[i+1:]
+ } else {
+ pkg := w.currPkg
+ if types.IsExported(name) {
+ pkg = localpkg
+ }
+ if s.Pkg != pkg {
+ Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
+ }
+ }
+
+ w.string(name)
+}
+
+func (w *exportWriter) typ(t *types.Type) {
+ w.data.uint64(w.p.typOff(t))
+}
+
+func (p *iexporter) newWriter() *exportWriter {
+ return &exportWriter{p: p}
+}
+
+func (w *exportWriter) flush() uint64 {
+ off := uint64(w.p.data0.Len())
+ io.Copy(&w.p.data0, &w.data)
+ return off
+}
+
+func (p *iexporter) typOff(t *types.Type) uint64 {
+ off, ok := p.typIndex[t]
+ if !ok {
+ w := p.newWriter()
+ w.doTyp(t)
+ off = predeclReserved + w.flush()
+ p.typIndex[t] = off
+ }
+ return off
+}
+
+func (w *exportWriter) startType(k itag) {
+ w.data.uint64(uint64(k))
+}
+
+func (w *exportWriter) doTyp(t *types.Type) {
+ if t.Sym != nil {
+ if t.Sym.Pkg == builtinpkg || t.Sym.Pkg == unsafepkg {
+ Fatalf("builtin type missing from typIndex: %v", t)
+ }
+
+ w.startType(definedType)
+ w.qualifiedIdent(typenod(t))
+ return
+ }
+
+ switch t.Etype {
+ case TPTR:
+ w.startType(pointerType)
+ w.typ(t.Elem())
+
+ case TSLICE:
+ w.startType(sliceType)
+ w.typ(t.Elem())
+
+ case TARRAY:
+ w.startType(arrayType)
+ w.uint64(uint64(t.NumElem()))
+ w.typ(t.Elem())
+
+ case TCHAN:
+ w.startType(chanType)
+ w.uint64(uint64(t.ChanDir()))
+ w.typ(t.Elem())
+
+ case TMAP:
+ w.startType(mapType)
+ w.typ(t.Key())
+ w.typ(t.Elem())
+
+ case TFUNC:
+ w.startType(signatureType)
+ w.setPkg(t.Pkg(), true)
+ w.signature(t)
+
+ case TSTRUCT:
+ w.startType(structType)
+ w.setPkg(t.Pkg(), true)
+
+ w.uint64(uint64(t.NumFields()))
+ for _, f := range t.FieldSlice() {
+ w.pos(f.Pos)
+ w.selector(f.Sym)
+ w.typ(f.Type)
+ w.bool(f.Embedded != 0)
+ w.string(f.Note)
+ }
+
+ case TINTER:
+ var embeddeds, methods []*types.Field
+ for _, m := range t.Methods().Slice() {
+ if m.Sym != nil {
+ methods = append(methods, m)
+ } else {
+ embeddeds = append(embeddeds, m)
+ }
+ }
+
+ w.startType(interfaceType)
+ w.setPkg(t.Pkg(), true)
+
+ w.uint64(uint64(len(embeddeds)))
+ for _, f := range embeddeds {
+ w.pos(f.Pos)
+ w.typ(f.Type)
+ }
+
+ w.uint64(uint64(len(methods)))
+ for _, f := range methods {
+ w.pos(f.Pos)
+ w.selector(f.Sym)
+ w.signature(f.Type)
+ }
+
+ default:
+ Fatalf("unexpected type: %v", t)
+ }
+}
+
+func (w *exportWriter) setPkg(pkg *types.Pkg, write bool) {
+ if pkg == nil {
+ // TODO(mdempsky): Proactively set Pkg for types and
+ // remove this fallback logic.
+ pkg = localpkg
+ }
+
+ if write {
+ w.pkg(pkg)
+ }
+
+ w.currPkg = pkg
+}
+
+func (w *exportWriter) signature(t *types.Type) {
+ w.paramList(t.Params().FieldSlice())
+ w.paramList(t.Results().FieldSlice())
+ if n := t.Params().NumFields(); n > 0 {
+ w.bool(t.Params().Field(n - 1).IsDDD())
+ }
+}
+
+func (w *exportWriter) paramList(fs []*types.Field) {
+ w.uint64(uint64(len(fs)))
+ for _, f := range fs {
+ w.param(f)
+ }
+}
+
+func (w *exportWriter) param(f *types.Field) {
+ w.pos(f.Pos)
+ w.localIdent(origSym(f.Sym), 0)
+ w.typ(f.Type)
+}
+
+func constTypeOf(typ *types.Type) Ctype {
+ switch typ {
+ case types.UntypedInt, types.UntypedRune:
+ return CTINT
+ case types.UntypedFloat:
+ return CTFLT
+ case types.UntypedComplex:
+ return CTCPLX
+ }
+
+ switch typ.Etype {
+ case TCHAN, TFUNC, TMAP, TNIL, TINTER, TPTR, TSLICE, TUNSAFEPTR:
+ return CTNIL
+ case TBOOL:
+ return CTBOOL
+ case TSTRING:
+ return CTSTR
+ case TINT, TINT8, TINT16, TINT32, TINT64,
+ TUINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINTPTR:
+ return CTINT
+ case TFLOAT32, TFLOAT64:
+ return CTFLT
+ case TCOMPLEX64, TCOMPLEX128:
+ return CTCPLX
+ }
+
+ Fatalf("unexpected constant type: %v", typ)
+ return 0
+}
+
+func (w *exportWriter) value(typ *types.Type, v Val) {
+ if vt := idealType(v.Ctype()); typ.IsUntyped() && typ != vt {
+ Fatalf("exporter: untyped type mismatch, have: %v, want: %v", typ, vt)
+ }
+ w.typ(typ)
+
+ // Each type has only one admissible constant representation,
+ // so we could type switch directly on v.U here. However,
+ // switching on the type increases symmetry with import logic
+ // and provides a useful consistency check.
+
+ switch constTypeOf(typ) {
+ case CTNIL:
+ // Only one value; nothing to encode.
+ _ = v.U.(*NilVal)
+ case CTBOOL:
+ w.bool(v.U.(bool))
+ case CTSTR:
+ w.string(v.U.(string))
+ case CTINT:
+ w.mpint(&v.U.(*Mpint).Val, typ)
+ case CTFLT:
+ w.mpfloat(&v.U.(*Mpflt).Val, typ)
+ case CTCPLX:
+ x := v.U.(*Mpcplx)
+ w.mpfloat(&x.Real.Val, typ)
+ w.mpfloat(&x.Imag.Val, typ)
+ }
+}
+
+func intSize(typ *types.Type) (signed bool, maxBytes uint) {
+ if typ.IsUntyped() {
+ return true, Mpprec / 8
+ }
+
+ switch typ.Etype {
+ case TFLOAT32, TCOMPLEX64:
+ return true, 3
+ case TFLOAT64, TCOMPLEX128:
+ return true, 7
+ }
+
+ signed = typ.IsSigned()
+ maxBytes = uint(typ.Size())
+
+ // The go/types API doesn't expose sizes to importers, so they
+ // don't know how big these types are.
+ switch typ.Etype {
+ case TINT, TUINT, TUINTPTR:
+ maxBytes = 8
+ }
+
+ return
+}
+
+// mpint exports a multi-precision integer.
+//
+// For unsigned types, small values are written out as a single
+// byte. Larger values are written out as a length-prefixed big-endian
+// byte string, where the length prefix is encoded as its complement.
+// For example, bytes 0, 1, and 2 directly represent the integer
+// values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-,
+// 2-, and 3-byte big-endian string follow.
+//
+// Encoding for signed types use the same general approach as for
+// unsigned types, except small values use zig-zag encoding and the
+// bottom bit of length prefix byte for large values is reserved as a
+// sign bit.
+//
+// The exact boundary between small and large encodings varies
+// according to the maximum number of bytes needed to encode a value
+// of type typ. As a special case, 8-bit types are always encoded as a
+// single byte.
+//
+// TODO(mdempsky): Is this level of complexity really worthwhile?
+func (w *exportWriter) mpint(x *big.Int, typ *types.Type) {
+ signed, maxBytes := intSize(typ)
+
+ negative := x.Sign() < 0
+ if !signed && negative {
+ Fatalf("negative unsigned integer; type %v, value %v", typ, x)
+ }
+
+ b := x.Bytes()
+ if len(b) > 0 && b[0] == 0 {
+ Fatalf("leading zeros")
+ }
+ if uint(len(b)) > maxBytes {
+ Fatalf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)
+ }
+
+ maxSmall := 256 - maxBytes
+ if signed {
+ maxSmall = 256 - 2*maxBytes
+ }
+ if maxBytes == 1 {
+ maxSmall = 256
+ }
+
+ // Check if x can use small value encoding.
+ if len(b) <= 1 {
+ var ux uint
+ if len(b) == 1 {
+ ux = uint(b[0])
+ }
+ if signed {
+ ux <<= 1
+ if negative {
+ ux--
+ }
+ }
+ if ux < maxSmall {
+ w.data.WriteByte(byte(ux))
+ return
+ }
+ }
+
+ n := 256 - uint(len(b))
+ if signed {
+ n = 256 - 2*uint(len(b))
+ if negative {
+ n |= 1
+ }
+ }
+ if n < maxSmall || n >= 256 {
+ Fatalf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)
+ }
+
+ w.data.WriteByte(byte(n))
+ w.data.Write(b)
+}
+
+// mpfloat exports a multi-precision floating point number.
+//
+// The number's value is decomposed into mantissa × 2**exponent, where
+// mantissa is an integer. The value is written out as mantissa (as a
+// multi-precision integer) and then the exponent, except exponent is
+// omitted if mantissa is zero.
+func (w *exportWriter) mpfloat(f *big.Float, typ *types.Type) {
+ if f.IsInf() {
+ Fatalf("infinite constant")
+ }
+
+ // Break into f = mant × 2**exp, with 0.5 <= mant < 1.
+ var mant big.Float
+ exp := int64(f.MantExp(&mant))
+
+ // Scale so that mant is an integer.
+ prec := mant.MinPrec()
+ mant.SetMantExp(&mant, int(prec))
+ exp -= int64(prec)
+
+ manti, acc := mant.Int(nil)
+ if acc != big.Exact {
+ Fatalf("mantissa scaling failed for %f (%s)", f, acc)
+ }
+ w.mpint(manti, typ)
+ if manti.Sign() != 0 {
+ w.int64(exp)
+ }
+}
+
+func (w *exportWriter) bool(b bool) bool {
+ var x uint64
+ if b {
+ x = 1
+ }
+ w.uint64(x)
+ return b
+}
+
+func (w *exportWriter) int64(x int64) { w.data.int64(x) }
+func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
+func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
+
+// Compiler-specific extensions.
+
+func (w *exportWriter) varExt(n *Node) {
+ w.linkname(n.Sym)
+ w.symIdx(n.Sym)
+}
+
+func (w *exportWriter) funcExt(n *Node) {
+ w.linkname(n.Sym)
+ w.symIdx(n.Sym)
+
+ // Escape analysis.
+ for _, fs := range &types.RecvsParams {
+ for _, f := range fs(n.Type).FieldSlice() {
+ w.string(f.Note)
+ }
+ }
+
+ // Inline body.
+ if n.Func.Inl != nil {
+ w.uint64(1 + uint64(n.Func.Inl.Cost))
+ if n.Func.ExportInline() {
+ w.p.doInline(n)
+ }
+
+ // Endlineno for inlined function.
+ if n.Name.Defn != nil {
+ w.pos(n.Name.Defn.Func.Endlineno)
+ } else {
+ // When the exported node was defined externally,
+ // e.g. io exports atomic.(*Value).Load or bytes exports errors.New.
+ // Keep it as we don't distinguish this case in iimport.go.
+ w.pos(n.Func.Endlineno)
+ }
+ } else {
+ w.uint64(0)
+ }
+}
+
+func (w *exportWriter) methExt(m *types.Field) {
+ w.bool(m.Nointerface())
+ w.funcExt(asNode(m.Type.Nname()))
+}
+
+func (w *exportWriter) linkname(s *types.Sym) {
+ w.string(s.Linkname)
+}
+
+func (w *exportWriter) symIdx(s *types.Sym) {
+ lsym := s.Linksym()
+ if lsym.PkgIdx > goobj.PkgIdxSelf || (lsym.PkgIdx == goobj.PkgIdxInvalid && !lsym.Indexed()) || s.Linkname != "" {
+ // Don't export index for non-package symbols, linkname'd symbols,
+ // and symbols without an index. They can only be referenced by
+ // name.
+ w.int64(-1)
+ } else {
+ // For a defined symbol, export its index.
+ // For re-exporting an imported symbol, pass its index through.
+ w.int64(int64(lsym.SymIdx))
+ }
+}
+
+func (w *exportWriter) typeExt(t *types.Type) {
+ // Export whether this type is marked notinheap.
+ w.bool(t.NotInHeap())
+ // For type T, export the index of type descriptor symbols of T and *T.
+ if i, ok := typeSymIdx[t]; ok {
+ w.int64(i[0])
+ w.int64(i[1])
+ return
+ }
+ w.symIdx(typesym(t))
+ w.symIdx(typesym(t.PtrTo()))
+}
+
+// Inline bodies.
+
+func (w *exportWriter) stmtList(list Nodes) {
+ for _, n := range list.Slice() {
+ w.node(n)
+ }
+ w.op(OEND)
+}
+
+func (w *exportWriter) node(n *Node) {
+ if opprec[n.Op] < 0 {
+ w.stmt(n)
+ } else {
+ w.expr(n)
+ }
+}
+
+// Caution: stmt will emit more than one node for statement nodes n that have a non-empty
+// n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
+func (w *exportWriter) stmt(n *Node) {
+ if n.Ninit.Len() > 0 && !stmtwithinit(n.Op) {
+ // can't use stmtList here since we don't want the final OEND
+ for _, n := range n.Ninit.Slice() {
+ w.stmt(n)
+ }
+ }
+
+ switch op := n.Op; op {
+ case ODCL:
+ w.op(ODCL)
+ w.pos(n.Left.Pos)
+ w.localName(n.Left)
+ w.typ(n.Left.Type)
+
+ // case ODCLFIELD:
+ // unimplemented - handled by default case
+
+ case OAS:
+ // Don't export "v = <N>" initializing statements, hope they're always
+ // preceded by the DCL which will be re-parsed and typecheck to reproduce
+ // the "v = <N>" again.
+ if n.Right != nil {
+ w.op(OAS)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ w.expr(n.Right)
+ }
+
+ case OASOP:
+ w.op(OASOP)
+ w.pos(n.Pos)
+ w.op(n.SubOp())
+ w.expr(n.Left)
+ if w.bool(!n.Implicit()) {
+ w.expr(n.Right)
+ }
+
+ case OAS2:
+ w.op(OAS2)
+ w.pos(n.Pos)
+ w.exprList(n.List)
+ w.exprList(n.Rlist)
+
+ case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ w.op(OAS2)
+ w.pos(n.Pos)
+ w.exprList(n.List)
+ w.exprList(asNodes([]*Node{n.Right}))
+
+ case ORETURN:
+ w.op(ORETURN)
+ w.pos(n.Pos)
+ w.exprList(n.List)
+
+ // case ORETJMP:
+ // unreachable - generated by compiler for trampolin routines
+
+ case OGO, ODEFER:
+ w.op(op)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+
+ case OIF:
+ w.op(OIF)
+ w.pos(n.Pos)
+ w.stmtList(n.Ninit)
+ w.expr(n.Left)
+ w.stmtList(n.Nbody)
+ w.stmtList(n.Rlist)
+
+ case OFOR:
+ w.op(OFOR)
+ w.pos(n.Pos)
+ w.stmtList(n.Ninit)
+ w.exprsOrNil(n.Left, n.Right)
+ w.stmtList(n.Nbody)
+
+ case ORANGE:
+ w.op(ORANGE)
+ w.pos(n.Pos)
+ w.stmtList(n.List)
+ w.expr(n.Right)
+ w.stmtList(n.Nbody)
+
+ case OSELECT, OSWITCH:
+ w.op(op)
+ w.pos(n.Pos)
+ w.stmtList(n.Ninit)
+ w.exprsOrNil(n.Left, nil)
+ w.caseList(n)
+
+ // case OCASE:
+ // handled by caseList
+
+ case OFALL:
+ w.op(OFALL)
+ w.pos(n.Pos)
+
+ case OBREAK, OCONTINUE:
+ w.op(op)
+ w.pos(n.Pos)
+ w.exprsOrNil(n.Left, nil)
+
+ case OEMPTY:
+ // nothing to emit
+
+ case OGOTO, OLABEL:
+ w.op(op)
+ w.pos(n.Pos)
+ w.string(n.Sym.Name)
+
+ default:
+ Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op)
+ }
+}
+
+func (w *exportWriter) caseList(sw *Node) {
+ namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil
+
+ cases := sw.List.Slice()
+ w.uint64(uint64(len(cases)))
+ for _, cas := range cases {
+ if cas.Op != OCASE {
+ Fatalf("expected OCASE, got %v", cas)
+ }
+ w.pos(cas.Pos)
+ w.stmtList(cas.List)
+ if namedTypeSwitch {
+ w.localName(cas.Rlist.First())
+ }
+ w.stmtList(cas.Nbody)
+ }
+}
+
+func (w *exportWriter) exprList(list Nodes) {
+ for _, n := range list.Slice() {
+ w.expr(n)
+ }
+ w.op(OEND)
+}
+
+func (w *exportWriter) expr(n *Node) {
+ // from nodefmt (fmt.go)
+ //
+ // nodefmt reverts nodes back to their original - we don't need to do
+ // it because we are not bound to produce valid Go syntax when exporting
+ //
+ // if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
+ // n = n.Orig
+ // }
+
+ // from exprfmt (fmt.go)
+ for n.Op == OPAREN || n.Implicit() && (n.Op == ODEREF || n.Op == OADDR || n.Op == ODOT || n.Op == ODOTPTR) {
+ n = n.Left
+ }
+
+ switch op := n.Op; op {
+ // expressions
+ // (somewhat closely following the structure of exprfmt in fmt.go)
+ case OLITERAL:
+ if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
+ w.expr(n.Orig)
+ break
+ }
+ w.op(OLITERAL)
+ w.pos(n.Pos)
+ w.value(n.Type, n.Val())
+
+ case ONAME:
+ // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
+ // but for export, this should be rendered as (*pkg.T).meth.
+ // These nodes have the special property that they are names with a left OTYPE and a right ONAME.
+ if n.isMethodExpression() {
+ w.op(OXDOT)
+ w.pos(n.Pos)
+ w.expr(n.Left) // n.Left.Op == OTYPE
+ w.selector(n.Right.Sym)
+ break
+ }
+
+ // Package scope name.
+ if (n.Class() == PEXTERN || n.Class() == PFUNC) && !n.isBlank() {
+ w.op(ONONAME)
+ w.qualifiedIdent(n)
+ break
+ }
+
+ // Function scope name.
+ w.op(ONAME)
+ w.localName(n)
+
+ // case OPACK, ONONAME:
+ // should have been resolved by typechecking - handled by default case
+
+ case OTYPE:
+ w.op(OTYPE)
+ w.typ(n.Type)
+
+ case OTYPESW:
+ w.op(OTYPESW)
+ w.pos(n.Pos)
+ var s *types.Sym
+ if n.Left != nil {
+ if n.Left.Op != ONONAME {
+ Fatalf("expected ONONAME, got %v", n.Left)
+ }
+ s = n.Left.Sym
+ }
+ w.localIdent(s, 0) // declared pseudo-variable, if any
+ w.exprsOrNil(n.Right, nil)
+
+ // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
+ // should have been resolved by typechecking - handled by default case
+
+ // case OCLOSURE:
+ // unimplemented - handled by default case
+
+ // case OCOMPLIT:
+ // should have been resolved by typechecking - handled by default case
+
+ case OPTRLIT:
+ w.op(OADDR)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+
+ case OSTRUCTLIT:
+ w.op(OSTRUCTLIT)
+ w.pos(n.Pos)
+ w.typ(n.Type)
+ w.elemList(n.List) // special handling of field names
+
+ case OARRAYLIT, OSLICELIT, OMAPLIT:
+ w.op(OCOMPLIT)
+ w.pos(n.Pos)
+ w.typ(n.Type)
+ w.exprList(n.List)
+
+ case OKEY:
+ w.op(OKEY)
+ w.pos(n.Pos)
+ w.exprsOrNil(n.Left, n.Right)
+
+ // case OSTRUCTKEY:
+ // unreachable - handled in case OSTRUCTLIT by elemList
+
+ case OCALLPART:
+ // An OCALLPART is an OXDOT before type checking.
+ w.op(OXDOT)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ // Right node should be ONAME
+ w.selector(n.Right.Sym)
+
+ case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+ w.op(OXDOT)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ w.selector(n.Sym)
+
+ case ODOTTYPE, ODOTTYPE2:
+ w.op(ODOTTYPE)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ w.typ(n.Type)
+
+ case OINDEX, OINDEXMAP:
+ w.op(OINDEX)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ w.expr(n.Right)
+
+ case OSLICE, OSLICESTR, OSLICEARR:
+ w.op(OSLICE)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ low, high, _ := n.SliceBounds()
+ w.exprsOrNil(low, high)
+
+ case OSLICE3, OSLICE3ARR:
+ w.op(OSLICE3)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ low, high, max := n.SliceBounds()
+ w.exprsOrNil(low, high)
+ w.expr(max)
+
+ case OCOPY, OCOMPLEX:
+ // treated like other builtin calls (see e.g., OREAL)
+ w.op(op)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ w.expr(n.Right)
+ w.op(OEND)
+
+ case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
+ w.op(OCONV)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ w.typ(n.Type)
+
+ case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
+ w.op(op)
+ w.pos(n.Pos)
+ if n.Left != nil {
+ w.expr(n.Left)
+ w.op(OEND)
+ } else {
+ w.exprList(n.List) // emits terminating OEND
+ }
+ // only append() calls may contain '...' arguments
+ if op == OAPPEND {
+ w.bool(n.IsDDD())
+ } else if n.IsDDD() {
+ Fatalf("exporter: unexpected '...' with %v call", op)
+ }
+
+ case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
+ w.op(OCALL)
+ w.pos(n.Pos)
+ w.stmtList(n.Ninit)
+ w.expr(n.Left)
+ w.exprList(n.List)
+ w.bool(n.IsDDD())
+
+ case OMAKEMAP, OMAKECHAN, OMAKESLICE:
+ w.op(op) // must keep separate from OMAKE for importer
+ w.pos(n.Pos)
+ w.typ(n.Type)
+ switch {
+ default:
+ // empty list
+ w.op(OEND)
+ case n.List.Len() != 0: // pre-typecheck
+ w.exprList(n.List) // emits terminating OEND
+ case n.Right != nil:
+ w.expr(n.Left)
+ w.expr(n.Right)
+ w.op(OEND)
+ case n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()):
+ w.expr(n.Left)
+ w.op(OEND)
+ }
+
+ // unary expressions
+ case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
+ w.op(op)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+
+ // binary expressions
+ case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
+ OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
+ w.op(op)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ w.expr(n.Right)
+
+ case OADDSTR:
+ w.op(OADDSTR)
+ w.pos(n.Pos)
+ w.exprList(n.List)
+
+ case ODCLCONST:
+ // if exporting, DCLCONST should just be removed as its usage
+ // has already been replaced with literals
+
+ default:
+ Fatalf("cannot export %v (%d) node\n"+
+ "\t==> please file an issue and assign to gri@", n.Op, int(n.Op))
+ }
+}
+
+func (w *exportWriter) op(op Op) {
+ w.uint64(uint64(op))
+}
+
+func (w *exportWriter) exprsOrNil(a, b *Node) {
+ ab := 0
+ if a != nil {
+ ab |= 1
+ }
+ if b != nil {
+ ab |= 2
+ }
+ w.uint64(uint64(ab))
+ if ab&1 != 0 {
+ w.expr(a)
+ }
+ if ab&2 != 0 {
+ w.node(b)
+ }
+}
+
+func (w *exportWriter) elemList(list Nodes) {
+ w.uint64(uint64(list.Len()))
+ for _, n := range list.Slice() {
+ w.selector(n.Sym)
+ w.expr(n.Left)
+ }
+}
+
+func (w *exportWriter) localName(n *Node) {
+ // Escape analysis happens after inline bodies are saved, but
+ // we're using the same ONAME nodes, so we might still see
+ // PAUTOHEAP here.
+ //
+ // Check for Stackcopy to identify PAUTOHEAP that came from
+ // PPARAM/PPARAMOUT, because we only want to include vargen in
+ // non-param names.
+ var v int32
+ if n.Class() == PAUTO || (n.Class() == PAUTOHEAP && n.Name.Param.Stackcopy == nil) {
+ v = n.Name.Vargen
+ }
+
+ w.localIdent(n.Sym, v)
+}
+
+func (w *exportWriter) localIdent(s *types.Sym, v int32) {
+ // Anonymous parameters.
+ if s == nil {
+ w.string("")
+ return
+ }
+
+ name := s.Name
+ if name == "_" {
+ w.string("_")
+ return
+ }
+
+ // TODO(mdempsky): Fix autotmp hack.
+ if i := strings.LastIndex(name, "."); i >= 0 && !strings.HasPrefix(name, ".autotmp_") {
+ Fatalf("unexpected dot in identifier: %v", name)
+ }
+
+ if v > 0 {
+ if strings.Contains(name, "·") {
+ Fatalf("exporter: unexpected · in symbol name")
+ }
+ name = fmt.Sprintf("%s·%d", name, v)
+ }
+
+ if !types.IsExported(name) && s.Pkg != w.currPkg {
+ Fatalf("weird package in name: %v => %v, not %q", s, name, w.currPkg.Path)
+ }
+
+ w.string(name)
+}
+
+type intWriter struct {
+ bytes.Buffer
+}
+
+func (w *intWriter) int64(x int64) {
+ var buf [binary.MaxVarintLen64]byte
+ n := binary.PutVarint(buf[:], x)
+ w.Write(buf[:n])
+}
+
+func (w *intWriter) uint64(x uint64) {
+ var buf [binary.MaxVarintLen64]byte
+ n := binary.PutUvarint(buf[:], x)
+ w.Write(buf[:n])
+}
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/iimport.go b/src/cmd/compile/internal/gc/iimport.go
new file mode 100644
index 0000000..c0114d0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -0,0 +1,1117 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Indexed package import.
+// See iexport.go for the export data format.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/bio"
+ "cmd/internal/goobj"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "math/big"
+ "os"
+ "strings"
+)
+
+// An iimporterAndOffset identifies an importer and an offset within
+// its data section.
+type iimporterAndOffset struct {
+ p *iimporter
+ off uint64
+}
+
+var (
+ // declImporter maps from imported identifiers to an importer
+ // and offset where that identifier's declaration can be read.
+ declImporter = map[*types.Sym]iimporterAndOffset{}
+
+ // inlineImporter is like declImporter, but for inline bodies
+ // for function and method symbols.
+ inlineImporter = map[*types.Sym]iimporterAndOffset{}
+)
+
+func expandDecl(n *Node) {
+ if n.Op != ONONAME {
+ return
+ }
+
+ r := importReaderFor(n, declImporter)
+ if r == nil {
+ // Can happen if user tries to reference an undeclared name.
+ return
+ }
+
+ r.doDecl(n)
+}
+
+func expandInline(fn *Node) {
+ if fn.Func.Inl.Body != nil {
+ return
+ }
+
+ r := importReaderFor(fn, inlineImporter)
+ if r == nil {
+ Fatalf("missing import reader for %v", fn)
+ }
+
+ r.doInline(fn)
+}
+
+func importReaderFor(n *Node, importers map[*types.Sym]iimporterAndOffset) *importReader {
+ x, ok := importers[n.Sym]
+ if !ok {
+ return nil
+ }
+
+ return x.p.newReader(x.off, n.Sym.Pkg)
+}
+
+type intReader struct {
+ *bio.Reader
+ pkg *types.Pkg
+}
+
+func (r *intReader) int64() int64 {
+ i, err := binary.ReadVarint(r.Reader)
+ if err != nil {
+ yyerror("import %q: read error: %v", r.pkg.Path, err)
+ errorexit()
+ }
+ return i
+}
+
+func (r *intReader) uint64() uint64 {
+ i, err := binary.ReadUvarint(r.Reader)
+ if err != nil {
+ yyerror("import %q: read error: %v", r.pkg.Path, err)
+ errorexit()
+ }
+ return i
+}
+
+func iimport(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType) {
+ ir := &intReader{in, pkg}
+
+ version := ir.uint64()
+ if version != iexportVersion {
+ yyerror("import %q: unknown export format version %d", pkg.Path, version)
+ errorexit()
+ }
+
+ sLen := ir.uint64()
+ dLen := ir.uint64()
+
+ // Map string (and data) section into memory as a single large
+ // string. This reduces heap fragmentation and allows
+ // returning individual substrings very efficiently.
+ data, err := mapFile(in.File(), in.Offset(), int64(sLen+dLen))
+ if err != nil {
+ yyerror("import %q: mapping input: %v", pkg.Path, err)
+ errorexit()
+ }
+ stringData := data[:sLen]
+ declData := data[sLen:]
+
+ in.MustSeek(int64(sLen+dLen), os.SEEK_CUR)
+
+ p := &iimporter{
+ ipkg: pkg,
+
+ pkgCache: map[uint64]*types.Pkg{},
+ posBaseCache: map[uint64]*src.PosBase{},
+ typCache: map[uint64]*types.Type{},
+
+ stringData: stringData,
+ declData: declData,
+ }
+
+ for i, pt := range predeclared() {
+ p.typCache[uint64(i)] = pt
+ }
+
+ // Declaration index.
+ for nPkgs := ir.uint64(); nPkgs > 0; nPkgs-- {
+ pkg := p.pkgAt(ir.uint64())
+ pkgName := p.stringAt(ir.uint64())
+ pkgHeight := int(ir.uint64())
+ if pkg.Name == "" {
+ pkg.Name = pkgName
+ pkg.Height = pkgHeight
+ numImport[pkgName]++
+
+ // TODO(mdempsky): This belongs somewhere else.
+ pkg.Lookup("_").Def = asTypesNode(nblank)
+ } else {
+ if pkg.Name != pkgName {
+ Fatalf("conflicting package names %v and %v for path %q", pkg.Name, pkgName, pkg.Path)
+ }
+ if pkg.Height != pkgHeight {
+ Fatalf("conflicting package heights %v and %v for path %q", pkg.Height, pkgHeight, pkg.Path)
+ }
+ }
+
+ for nSyms := ir.uint64(); nSyms > 0; nSyms-- {
+ s := pkg.Lookup(p.stringAt(ir.uint64()))
+ off := ir.uint64()
+
+ if _, ok := declImporter[s]; ok {
+ continue
+ }
+ declImporter[s] = iimporterAndOffset{p, off}
+
+ // Create stub declaration. If used, this will
+ // be overwritten by expandDecl.
+ if s.Def != nil {
+ Fatalf("unexpected definition for %v: %v", s, asNode(s.Def))
+ }
+ s.Def = asTypesNode(npos(src.NoXPos, dclname(s)))
+ }
+ }
+
+ // Inline body index.
+ for nPkgs := ir.uint64(); nPkgs > 0; nPkgs-- {
+ pkg := p.pkgAt(ir.uint64())
+
+ for nSyms := ir.uint64(); nSyms > 0; nSyms-- {
+ s := pkg.Lookup(p.stringAt(ir.uint64()))
+ off := ir.uint64()
+
+ if _, ok := inlineImporter[s]; ok {
+ continue
+ }
+ inlineImporter[s] = iimporterAndOffset{p, off}
+ }
+ }
+
+ // Fingerprint.
+ _, err = io.ReadFull(in, fingerprint[:])
+ if err != nil {
+ yyerror("import %s: error reading fingerprint", pkg.Path)
+ errorexit()
+ }
+ return fingerprint
+}
+
+type iimporter struct {
+ ipkg *types.Pkg
+
+ pkgCache map[uint64]*types.Pkg
+ posBaseCache map[uint64]*src.PosBase
+ typCache map[uint64]*types.Type
+
+ stringData string
+ declData string
+}
+
+func (p *iimporter) stringAt(off uint64) string {
+ var x [binary.MaxVarintLen64]byte
+ n := copy(x[:], p.stringData[off:])
+
+ slen, n := binary.Uvarint(x[:n])
+ if n <= 0 {
+ Fatalf("varint failed")
+ }
+ spos := off + uint64(n)
+ return p.stringData[spos : spos+slen]
+}
+
+func (p *iimporter) posBaseAt(off uint64) *src.PosBase {
+ if posBase, ok := p.posBaseCache[off]; ok {
+ return posBase
+ }
+
+ file := p.stringAt(off)
+ posBase := src.NewFileBase(file, file)
+ p.posBaseCache[off] = posBase
+ return posBase
+}
+
+func (p *iimporter) pkgAt(off uint64) *types.Pkg {
+ if pkg, ok := p.pkgCache[off]; ok {
+ return pkg
+ }
+
+ pkg := p.ipkg
+ if pkgPath := p.stringAt(off); pkgPath != "" {
+ pkg = types.NewPkg(pkgPath, "")
+ }
+ p.pkgCache[off] = pkg
+ return pkg
+}
+
+// An importReader keeps state for reading an individual imported
+// object (declaration or inline body).
+type importReader struct {
+ strings.Reader
+ p *iimporter
+
+ currPkg *types.Pkg
+ prevBase *src.PosBase
+ prevLine int64
+ prevColumn int64
+}
+
+func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader {
+ r := &importReader{
+ p: p,
+ currPkg: pkg,
+ }
+ // (*strings.Reader).Reset wasn't added until Go 1.7, and we
+ // need to build with Go 1.4.
+ r.Reader = *strings.NewReader(p.declData[off:])
+ return r
+}
+
+func (r *importReader) string() string { return r.p.stringAt(r.uint64()) }
+func (r *importReader) posBase() *src.PosBase { return r.p.posBaseAt(r.uint64()) }
+func (r *importReader) pkg() *types.Pkg { return r.p.pkgAt(r.uint64()) }
+
+func (r *importReader) setPkg() {
+ r.currPkg = r.pkg()
+}
+
+func (r *importReader) doDecl(n *Node) {
+ if n.Op != ONONAME {
+ Fatalf("doDecl: unexpected Op for %v: %v", n.Sym, n.Op)
+ }
+
+ tag := r.byte()
+ pos := r.pos()
+
+ switch tag {
+ case 'A':
+ typ := r.typ()
+
+ importalias(r.p.ipkg, pos, n.Sym, typ)
+
+ case 'C':
+ typ, val := r.value()
+
+ importconst(r.p.ipkg, pos, n.Sym, typ, val)
+
+ case 'F':
+ typ := r.signature(nil)
+
+ importfunc(r.p.ipkg, pos, n.Sym, typ)
+ r.funcExt(n)
+
+ case 'T':
+ // Types can be recursive. We need to setup a stub
+ // declaration before recursing.
+ t := importtype(r.p.ipkg, pos, n.Sym)
+
+ // We also need to defer width calculations until
+ // after the underlying type has been assigned.
+ defercheckwidth()
+ underlying := r.typ()
+ setUnderlying(t, underlying)
+ resumecheckwidth()
+
+ if underlying.IsInterface() {
+ r.typeExt(t)
+ break
+ }
+
+ ms := make([]*types.Field, r.uint64())
+ for i := range ms {
+ mpos := r.pos()
+ msym := r.ident()
+ recv := r.param()
+ mtyp := r.signature(recv)
+
+ f := types.NewField()
+ f.Pos = mpos
+ f.Sym = msym
+ f.Type = mtyp
+ ms[i] = f
+
+ m := newfuncnamel(mpos, methodSym(recv.Type, msym))
+ m.Type = mtyp
+ m.SetClass(PFUNC)
+ // methodSym already marked m.Sym as a function.
+
+ // (comment from parser.go)
+ // inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
+ // (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
+ // out by typecheck's lookdot as this $$.ttype. So by providing
+ // this back link here we avoid special casing there.
+ mtyp.SetNname(asTypesNode(m))
+ }
+ t.Methods().Set(ms)
+
+ r.typeExt(t)
+ for _, m := range ms {
+ r.methExt(m)
+ }
+
+ case 'V':
+ typ := r.typ()
+
+ importvar(r.p.ipkg, pos, n.Sym, typ)
+ r.varExt(n)
+
+ default:
+ Fatalf("unexpected tag: %v", tag)
+ }
+}
+
+func (p *importReader) value() (typ *types.Type, v Val) {
+ typ = p.typ()
+
+ switch constTypeOf(typ) {
+ case CTNIL:
+ v.U = &NilVal{}
+ case CTBOOL:
+ v.U = p.bool()
+ case CTSTR:
+ v.U = p.string()
+ case CTINT:
+ x := new(Mpint)
+ x.Rune = typ == types.UntypedRune
+ p.mpint(&x.Val, typ)
+ v.U = x
+ case CTFLT:
+ x := newMpflt()
+ p.float(x, typ)
+ v.U = x
+ case CTCPLX:
+ x := newMpcmplx()
+ p.float(&x.Real, typ)
+ p.float(&x.Imag, typ)
+ v.U = x
+ }
+ return
+}
+
+func (p *importReader) mpint(x *big.Int, typ *types.Type) {
+ signed, maxBytes := intSize(typ)
+
+ maxSmall := 256 - maxBytes
+ if signed {
+ maxSmall = 256 - 2*maxBytes
+ }
+ if maxBytes == 1 {
+ maxSmall = 256
+ }
+
+ n, _ := p.ReadByte()
+ if uint(n) < maxSmall {
+ v := int64(n)
+ if signed {
+ v >>= 1
+ if n&1 != 0 {
+ v = ^v
+ }
+ }
+ x.SetInt64(v)
+ return
+ }
+
+ v := -n
+ if signed {
+ v = -(n &^ 1) >> 1
+ }
+ if v < 1 || uint(v) > maxBytes {
+ Fatalf("weird decoding: %v, %v => %v", n, signed, v)
+ }
+ b := make([]byte, v)
+ p.Read(b)
+ x.SetBytes(b)
+ if signed && n&1 != 0 {
+ x.Neg(x)
+ }
+}
+
+func (p *importReader) float(x *Mpflt, typ *types.Type) {
+ var mant big.Int
+ p.mpint(&mant, typ)
+ m := x.Val.SetInt(&mant)
+ if m.Sign() == 0 {
+ return
+ }
+ m.SetMantExp(m, int(p.int64()))
+}
+
+func (r *importReader) ident() *types.Sym {
+ name := r.string()
+ if name == "" {
+ return nil
+ }
+ pkg := r.currPkg
+ if types.IsExported(name) {
+ pkg = localpkg
+ }
+ return pkg.Lookup(name)
+}
+
+func (r *importReader) qualifiedIdent() *types.Sym {
+ name := r.string()
+ pkg := r.pkg()
+ return pkg.Lookup(name)
+}
+
+func (r *importReader) pos() src.XPos {
+ delta := r.int64()
+ r.prevColumn += delta >> 1
+ if delta&1 != 0 {
+ delta = r.int64()
+ r.prevLine += delta >> 1
+ if delta&1 != 0 {
+ r.prevBase = r.posBase()
+ }
+ }
+
+ if (r.prevBase == nil || r.prevBase.AbsFilename() == "") && r.prevLine == 0 && r.prevColumn == 0 {
+ // TODO(mdempsky): Remove once we reliably write
+ // position information for all nodes.
+ return src.NoXPos
+ }
+
+ if r.prevBase == nil {
+ Fatalf("missing posbase")
+ }
+ pos := src.MakePos(r.prevBase, uint(r.prevLine), uint(r.prevColumn))
+ return Ctxt.PosTable.XPos(pos)
+}
+
+func (r *importReader) typ() *types.Type {
+ return r.p.typAt(r.uint64())
+}
+
+func (p *iimporter) typAt(off uint64) *types.Type {
+ t, ok := p.typCache[off]
+ if !ok {
+ if off < predeclReserved {
+ Fatalf("predeclared type missing from cache: %d", off)
+ }
+ t = p.newReader(off-predeclReserved, nil).typ1()
+ p.typCache[off] = t
+ }
+ return t
+}
+
+func (r *importReader) typ1() *types.Type {
+ switch k := r.kind(); k {
+ default:
+ Fatalf("unexpected kind tag in %q: %v", r.p.ipkg.Path, k)
+ return nil
+
+ case definedType:
+ // We might be called from within doInline, in which
+ // case Sym.Def can point to declared parameters
+ // instead of the top-level types. Also, we don't
+ // support inlining functions with local defined
+ // types. Therefore, this must be a package-scope
+ // type.
+ n := asNode(r.qualifiedIdent().PkgDef())
+ if n.Op == ONONAME {
+ expandDecl(n)
+ }
+ if n.Op != OTYPE {
+ Fatalf("expected OTYPE, got %v: %v, %v", n.Op, n.Sym, n)
+ }
+ return n.Type
+ case pointerType:
+ return types.NewPtr(r.typ())
+ case sliceType:
+ return types.NewSlice(r.typ())
+ case arrayType:
+ n := r.uint64()
+ return types.NewArray(r.typ(), int64(n))
+ case chanType:
+ dir := types.ChanDir(r.uint64())
+ return types.NewChan(r.typ(), dir)
+ case mapType:
+ return types.NewMap(r.typ(), r.typ())
+
+ case signatureType:
+ r.setPkg()
+ return r.signature(nil)
+
+ case structType:
+ r.setPkg()
+
+ fs := make([]*types.Field, r.uint64())
+ for i := range fs {
+ pos := r.pos()
+ sym := r.ident()
+ typ := r.typ()
+ emb := r.bool()
+ note := r.string()
+
+ f := types.NewField()
+ f.Pos = pos
+ f.Sym = sym
+ f.Type = typ
+ if emb {
+ f.Embedded = 1
+ }
+ f.Note = note
+ fs[i] = f
+ }
+
+ t := types.New(TSTRUCT)
+ t.SetPkg(r.currPkg)
+ t.SetFields(fs)
+ return t
+
+ case interfaceType:
+ r.setPkg()
+
+ embeddeds := make([]*types.Field, r.uint64())
+ for i := range embeddeds {
+ pos := r.pos()
+ typ := r.typ()
+
+ f := types.NewField()
+ f.Pos = pos
+ f.Type = typ
+ embeddeds[i] = f
+ }
+
+ methods := make([]*types.Field, r.uint64())
+ for i := range methods {
+ pos := r.pos()
+ sym := r.ident()
+ typ := r.signature(fakeRecvField())
+
+ f := types.NewField()
+ f.Pos = pos
+ f.Sym = sym
+ f.Type = typ
+ methods[i] = f
+ }
+
+ t := types.New(TINTER)
+ t.SetPkg(r.currPkg)
+ t.SetInterface(append(embeddeds, methods...))
+
+ // Ensure we expand the interface in the frontend (#25055).
+ checkwidth(t)
+ return t
+ }
+}
+
+func (r *importReader) kind() itag {
+ return itag(r.uint64())
+}
+
+func (r *importReader) signature(recv *types.Field) *types.Type {
+ params := r.paramList()
+ results := r.paramList()
+ if n := len(params); n > 0 {
+ params[n-1].SetIsDDD(r.bool())
+ }
+ t := functypefield(recv, params, results)
+ t.SetPkg(r.currPkg)
+ return t
+}
+
+func (r *importReader) paramList() []*types.Field {
+ fs := make([]*types.Field, r.uint64())
+ for i := range fs {
+ fs[i] = r.param()
+ }
+ return fs
+}
+
+func (r *importReader) param() *types.Field {
+ f := types.NewField()
+ f.Pos = r.pos()
+ f.Sym = r.ident()
+ f.Type = r.typ()
+ return f
+}
+
+func (r *importReader) bool() bool {
+ return r.uint64() != 0
+}
+
+func (r *importReader) int64() int64 {
+ n, err := binary.ReadVarint(r)
+ if err != nil {
+ Fatalf("readVarint: %v", err)
+ }
+ return n
+}
+
+func (r *importReader) uint64() uint64 {
+ n, err := binary.ReadUvarint(r)
+ if err != nil {
+ Fatalf("readVarint: %v", err)
+ }
+ return n
+}
+
+func (r *importReader) byte() byte {
+ x, err := r.ReadByte()
+ if err != nil {
+ Fatalf("declReader.ReadByte: %v", err)
+ }
+ return x
+}
+
+// Compiler-specific extensions.
+
+func (r *importReader) varExt(n *Node) {
+ r.linkname(n.Sym)
+ r.symIdx(n.Sym)
+}
+
+func (r *importReader) funcExt(n *Node) {
+ r.linkname(n.Sym)
+ r.symIdx(n.Sym)
+
+ // Escape analysis.
+ for _, fs := range &types.RecvsParams {
+ for _, f := range fs(n.Type).FieldSlice() {
+ f.Note = r.string()
+ }
+ }
+
+ // Inline body.
+ if u := r.uint64(); u > 0 {
+ n.Func.Inl = &Inline{
+ Cost: int32(u - 1),
+ }
+ n.Func.Endlineno = r.pos()
+ }
+}
+
+func (r *importReader) methExt(m *types.Field) {
+ if r.bool() {
+ m.SetNointerface(true)
+ }
+ r.funcExt(asNode(m.Type.Nname()))
+}
+
+func (r *importReader) linkname(s *types.Sym) {
+ s.Linkname = r.string()
+}
+
+func (r *importReader) symIdx(s *types.Sym) {
+ lsym := s.Linksym()
+ idx := int32(r.int64())
+ if idx != -1 {
+ if s.Linkname != "" {
+ Fatalf("bad index for linknamed symbol: %v %d\n", lsym, idx)
+ }
+ lsym.SymIdx = idx
+ lsym.Set(obj.AttrIndexed, true)
+ }
+}
+
+func (r *importReader) typeExt(t *types.Type) {
+ t.SetNotInHeap(r.bool())
+ i, pi := r.int64(), r.int64()
+ if i != -1 && pi != -1 {
+ typeSymIdx[t] = [2]int64{i, pi}
+ }
+}
+
+// Map imported type T to the index of type descriptor symbols of T and *T,
+// so we can use index to reference the symbol.
+var typeSymIdx = make(map[*types.Type][2]int64)
+
+func (r *importReader) doInline(n *Node) {
+ if len(n.Func.Inl.Body) != 0 {
+ Fatalf("%v already has inline body", n)
+ }
+
+ funchdr(n)
+ body := r.stmtList()
+ funcbody()
+ if body == nil {
+ //
+ // Make sure empty body is not interpreted as
+ // no inlineable body (see also parser.fnbody)
+ // (not doing so can cause significant performance
+ // degradation due to unnecessary calls to empty
+ // functions).
+ body = []*Node{}
+ }
+ n.Func.Inl.Body = body
+
+ importlist = append(importlist, n)
+
+ if Debug.E > 0 && Debug.m > 2 {
+ if Debug.m > 3 {
+ fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body))
+ } else {
+ fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body))
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Inlined function bodies
+
+// Approach: Read nodes and use them to create/declare the same data structures
+// as done originally by the (hidden) parser by closely following the parser's
+// original code. In other words, "parsing" the import data (which happens to
+// be encoded in binary rather textual form) is the best way at the moment to
+// re-establish the syntax tree's invariants. At some future point we might be
+// able to avoid this round-about way and create the rewritten nodes directly,
+// possibly avoiding a lot of duplicate work (name resolution, type checking).
+//
+// Refined nodes (e.g., ODOTPTR as a refinement of OXDOT) are exported as their
+// unrefined nodes (since this is what the importer uses). The respective case
+// entries are unreachable in the importer.
+
+func (r *importReader) stmtList() []*Node {
+ var list []*Node
+ for {
+ n := r.node()
+ if n == nil {
+ break
+ }
+ // OBLOCK nodes may be created when importing ODCL nodes - unpack them
+ if n.Op == OBLOCK {
+ list = append(list, n.List.Slice()...)
+ } else {
+ list = append(list, n)
+ }
+
+ }
+ return list
+}
+
+func (r *importReader) caseList(sw *Node) []*Node {
+ namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil
+
+ cases := make([]*Node, r.uint64())
+ for i := range cases {
+ cas := nodl(r.pos(), OCASE, nil, nil)
+ cas.List.Set(r.stmtList())
+ if namedTypeSwitch {
+ // Note: per-case variables will have distinct, dotted
+ // names after import. That's okay: swt.go only needs
+ // Sym for diagnostics anyway.
+ caseVar := newnamel(cas.Pos, r.ident())
+ declare(caseVar, dclcontext)
+ cas.Rlist.Set1(caseVar)
+ caseVar.Name.Defn = sw.Left
+ }
+ cas.Nbody.Set(r.stmtList())
+ cases[i] = cas
+ }
+ return cases
+}
+
+func (r *importReader) exprList() []*Node {
+ var list []*Node
+ for {
+ n := r.expr()
+ if n == nil {
+ break
+ }
+ list = append(list, n)
+ }
+ return list
+}
+
+func (r *importReader) expr() *Node {
+ n := r.node()
+ if n != nil && n.Op == OBLOCK {
+ Fatalf("unexpected block node: %v", n)
+ }
+ return n
+}
+
+// TODO(gri) split into expr and stmt
+func (r *importReader) node() *Node {
+ switch op := r.op(); op {
+ // expressions
+ // case OPAREN:
+ // unreachable - unpacked by exporter
+
+ case OLITERAL:
+ pos := r.pos()
+ typ, val := r.value()
+
+ n := npos(pos, nodlit(val))
+ n.Type = typ
+ return n
+
+ case ONONAME:
+ return mkname(r.qualifiedIdent())
+
+ case ONAME:
+ return mkname(r.ident())
+
+ // case OPACK, ONONAME:
+ // unreachable - should have been resolved by typechecking
+
+ case OTYPE:
+ return typenod(r.typ())
+
+ case OTYPESW:
+ n := nodl(r.pos(), OTYPESW, nil, nil)
+ if s := r.ident(); s != nil {
+ n.Left = npos(n.Pos, newnoname(s))
+ }
+ n.Right, _ = r.exprsOrNil()
+ return n
+
+ // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
+ // unreachable - should have been resolved by typechecking
+
+ // case OCLOSURE:
+ // unimplemented
+
+ // case OPTRLIT:
+ // unreachable - mapped to case OADDR below by exporter
+
+ case OSTRUCTLIT:
+ // TODO(mdempsky): Export position information for OSTRUCTKEY nodes.
+ savedlineno := lineno
+ lineno = r.pos()
+ n := nodl(lineno, OCOMPLIT, nil, typenod(r.typ()))
+ n.List.Set(r.elemList()) // special handling of field names
+ lineno = savedlineno
+ return n
+
+ // case OARRAYLIT, OSLICELIT, OMAPLIT:
+ // unreachable - mapped to case OCOMPLIT below by exporter
+
+ case OCOMPLIT:
+ n := nodl(r.pos(), OCOMPLIT, nil, typenod(r.typ()))
+ n.List.Set(r.exprList())
+ return n
+
+ case OKEY:
+ pos := r.pos()
+ left, right := r.exprsOrNil()
+ return nodl(pos, OKEY, left, right)
+
+ // case OSTRUCTKEY:
+ // unreachable - handled in case OSTRUCTLIT by elemList
+
+ // case OCALLPART:
+ // unreachable - mapped to case OXDOT below by exporter
+
+ // case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+ // unreachable - mapped to case OXDOT below by exporter
+
+ case OXDOT:
+ // see parser.new_dotname
+ return npos(r.pos(), nodSym(OXDOT, r.expr(), r.ident()))
+
+ // case ODOTTYPE, ODOTTYPE2:
+ // unreachable - mapped to case ODOTTYPE below by exporter
+
+ case ODOTTYPE:
+ n := nodl(r.pos(), ODOTTYPE, r.expr(), nil)
+ n.Type = r.typ()
+ return n
+
+ // case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
+ // unreachable - mapped to cases below by exporter
+
+ case OINDEX:
+ return nodl(r.pos(), op, r.expr(), r.expr())
+
+ case OSLICE, OSLICE3:
+ n := nodl(r.pos(), op, r.expr(), nil)
+ low, high := r.exprsOrNil()
+ var max *Node
+ if n.Op.IsSlice3() {
+ max = r.expr()
+ }
+ n.SetSliceBounds(low, high, max)
+ return n
+
+ // case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
+ // unreachable - mapped to OCONV case below by exporter
+
+ case OCONV:
+ n := nodl(r.pos(), OCONV, r.expr(), nil)
+ n.Type = r.typ()
+ return n
+
+ case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
+ n := npos(r.pos(), builtinCall(op))
+ n.List.Set(r.exprList())
+ if op == OAPPEND {
+ n.SetIsDDD(r.bool())
+ }
+ return n
+
+ // case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
+ // unreachable - mapped to OCALL case below by exporter
+
+ case OCALL:
+ n := nodl(r.pos(), OCALL, nil, nil)
+ n.Ninit.Set(r.stmtList())
+ n.Left = r.expr()
+ n.List.Set(r.exprList())
+ n.SetIsDDD(r.bool())
+ return n
+
+ case OMAKEMAP, OMAKECHAN, OMAKESLICE:
+ n := npos(r.pos(), builtinCall(OMAKE))
+ n.List.Append(typenod(r.typ()))
+ n.List.Append(r.exprList()...)
+ return n
+
+ // unary expressions
+ case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
+ return nodl(r.pos(), op, r.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 nodl(r.pos(), op, r.expr(), r.expr())
+
+ case OADDSTR:
+ pos := r.pos()
+ list := r.exprList()
+ x := npos(pos, list[0])
+ for _, y := range list[1:] {
+ x = nodl(pos, OADD, x, y)
+ }
+ return x
+
+ // --------------------------------------------------------------------
+ // statements
+ case ODCL:
+ pos := r.pos()
+ lhs := npos(pos, dclname(r.ident()))
+ typ := typenod(r.typ())
+ return npos(pos, liststmt(variter([]*Node{lhs}, typ, nil))) // TODO(gri) avoid list creation
+
+ // case ODCLFIELD:
+ // unimplemented
+
+ // case OAS, OASWB:
+ // unreachable - mapped to OAS case below by exporter
+
+ case OAS:
+ return nodl(r.pos(), OAS, r.expr(), r.expr())
+
+ case OASOP:
+ n := nodl(r.pos(), OASOP, nil, nil)
+ n.SetSubOp(r.op())
+ n.Left = r.expr()
+ if !r.bool() {
+ n.Right = nodintconst(1)
+ n.SetImplicit(true)
+ } else {
+ n.Right = r.expr()
+ }
+ return n
+
+ // case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ // unreachable - mapped to OAS2 case below by exporter
+
+ case OAS2:
+ n := nodl(r.pos(), OAS2, nil, nil)
+ n.List.Set(r.exprList())
+ n.Rlist.Set(r.exprList())
+ return n
+
+ case ORETURN:
+ n := nodl(r.pos(), ORETURN, nil, nil)
+ n.List.Set(r.exprList())
+ return n
+
+ // case ORETJMP:
+ // unreachable - generated by compiler for trampolin routines (not exported)
+
+ case OGO, ODEFER:
+ return nodl(r.pos(), op, r.expr(), nil)
+
+ case OIF:
+ n := nodl(r.pos(), OIF, nil, nil)
+ n.Ninit.Set(r.stmtList())
+ n.Left = r.expr()
+ n.Nbody.Set(r.stmtList())
+ n.Rlist.Set(r.stmtList())
+ return n
+
+ case OFOR:
+ n := nodl(r.pos(), OFOR, nil, nil)
+ n.Ninit.Set(r.stmtList())
+ n.Left, n.Right = r.exprsOrNil()
+ n.Nbody.Set(r.stmtList())
+ return n
+
+ case ORANGE:
+ n := nodl(r.pos(), ORANGE, nil, nil)
+ n.List.Set(r.stmtList())
+ n.Right = r.expr()
+ n.Nbody.Set(r.stmtList())
+ return n
+
+ case OSELECT, OSWITCH:
+ n := nodl(r.pos(), op, nil, nil)
+ n.Ninit.Set(r.stmtList())
+ n.Left, _ = r.exprsOrNil()
+ n.List.Set(r.caseList(n))
+ return n
+
+ // case OCASE:
+ // handled by caseList
+
+ case OFALL:
+ n := nodl(r.pos(), OFALL, nil, nil)
+ return n
+
+ case OBREAK, OCONTINUE:
+ pos := r.pos()
+ left, _ := r.exprsOrNil()
+ if left != nil {
+ left = newname(left.Sym)
+ }
+ return nodl(pos, op, left, nil)
+
+ // case OEMPTY:
+ // unreachable - not emitted by exporter
+
+ case OGOTO, OLABEL:
+ n := nodl(r.pos(), op, nil, nil)
+ n.Sym = lookup(r.string())
+ return n
+
+ case OEND:
+ return nil
+
+ default:
+ Fatalf("cannot import %v (%d) node\n"+
+ "\t==> please file an issue and assign to gri@", op, int(op))
+ panic("unreachable") // satisfy compiler
+ }
+}
+
+func (r *importReader) op() Op {
+ return Op(r.uint64())
+}
+
+func (r *importReader) elemList() []*Node {
+ c := r.uint64()
+ list := make([]*Node, c)
+ for i := range list {
+ s := r.ident()
+ list[i] = nodSym(OSTRUCTKEY, r.expr(), s)
+ }
+ return list
+}
+
+func (r *importReader) exprsOrNil() (a, b *Node) {
+ ab := r.uint64()
+ if ab&1 != 0 {
+ a = r.expr()
+ }
+ if ab&2 != 0 {
+ b = r.node()
+ }
+ return
+}
diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
new file mode 100644
index 0000000..ec9cc4b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/init.go
@@ -0,0 +1,109 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+)
+
+// A function named init is a special case.
+// It is called by the initialization before main is run.
+// To make it unique within a package and also uncallable,
+// the name, normally "pkg.init", is altered to "pkg.init.0".
+var renameinitgen int
+
+// Dummy function for autotmps generated during typechecking.
+var dummyInitFn = nod(ODCLFUNC, nil, nil)
+
+func renameinit() *types.Sym {
+ s := lookupN("init.", renameinitgen)
+ renameinitgen++
+ return s
+}
+
+// fninit makes an initialization record for the package.
+// See runtime/proc.go:initTask for its layout.
+// The 3 tasks for initialization are:
+// 1) Initialize all of the packages the current package depends on.
+// 2) Initialize all the variables that have initializers.
+// 3) Run any init functions.
+func fninit(n []*Node) {
+ nf := initOrder(n)
+
+ var deps []*obj.LSym // initTask records for packages the current package depends on
+ var fns []*obj.LSym // functions to call for package initialization
+
+ // Find imported packages with init tasks.
+ for _, s := range types.InitSyms {
+ deps = append(deps, s.Linksym())
+ }
+
+ // Make a function that contains all the initialization statements.
+ if len(nf) > 0 {
+ lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt
+ initializers := lookup("init")
+ fn := dclfunc(initializers, nod(OTFUNC, nil, nil))
+ for _, dcl := range dummyInitFn.Func.Dcl {
+ dcl.Name.Curfn = fn
+ }
+ fn.Func.Dcl = append(fn.Func.Dcl, dummyInitFn.Func.Dcl...)
+ dummyInitFn.Func.Dcl = nil
+
+ fn.Nbody.Set(nf)
+ funcbody()
+
+ fn = typecheck(fn, ctxStmt)
+ Curfn = fn
+ typecheckslice(nf, ctxStmt)
+ Curfn = nil
+ xtop = append(xtop, fn)
+ fns = append(fns, initializers.Linksym())
+ }
+ if dummyInitFn.Func.Dcl != nil {
+ // We only generate temps using dummyInitFn if there
+ // are package-scope initialization statements, so
+ // something's weird if we get here.
+ Fatalf("dummyInitFn still has declarations")
+ }
+ dummyInitFn = nil
+
+ // Record user init functions.
+ for i := 0; i < renameinitgen; i++ {
+ s := lookupN("init.", i)
+ fn := asNode(s.Def).Name.Defn
+ // Skip init functions with empty bodies.
+ if fn.Nbody.Len() == 1 && fn.Nbody.First().Op == OEMPTY {
+ continue
+ }
+ fns = append(fns, s.Linksym())
+ }
+
+ if len(deps) == 0 && len(fns) == 0 && localpkg.Name != "main" && localpkg.Name != "runtime" {
+ return // nothing to initialize
+ }
+
+ // Make an .inittask structure.
+ sym := lookup(".inittask")
+ nn := newname(sym)
+ nn.Type = types.Types[TUINT8] // dummy type
+ nn.SetClass(PEXTERN)
+ sym.Def = asTypesNode(nn)
+ exportsym(nn)
+ lsym := sym.Linksym()
+ ot := 0
+ ot = duintptr(lsym, ot, 0) // state: not initialized yet
+ ot = duintptr(lsym, ot, uint64(len(deps)))
+ ot = duintptr(lsym, ot, uint64(len(fns)))
+ for _, d := range deps {
+ ot = dsymptr(lsym, ot, d, 0)
+ }
+ for _, f := range fns {
+ ot = dsymptr(lsym, ot, f, 0)
+ }
+ // An initTask has pointers, but none into the Go heap.
+ // It's not quite read only, the state field must be modifiable.
+ ggloblsym(lsym, int32(ot), obj.NOPTR)
+}
diff --git a/src/cmd/compile/internal/gc/initorder.go b/src/cmd/compile/internal/gc/initorder.go
new file mode 100644
index 0000000..e2084fd
--- /dev/null
+++ b/src/cmd/compile/internal/gc/initorder.go
@@ -0,0 +1,358 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "bytes"
+ "container/heap"
+ "fmt"
+)
+
+// Package initialization
+//
+// Here we implement the algorithm for ordering package-level variable
+// initialization. The spec is written in terms of variable
+// initialization, but multiple variables initialized by a single
+// assignment are handled together, so here we instead focus on
+// ordering initialization assignments. Conveniently, this maps well
+// to how we represent package-level initializations using the Node
+// AST.
+//
+// Assignments are in one of three phases: NotStarted, Pending, or
+// Done. For assignments in the Pending phase, we use Xoffset to
+// record the number of unique variable dependencies whose
+// initialization assignment is not yet Done. We also maintain a
+// "blocking" map that maps assignments back to all of the assignments
+// that depend on it.
+//
+// For example, for an initialization like:
+//
+// var x = f(a, b, b)
+// var a, b = g()
+//
+// the "x = f(a, b, b)" assignment depends on two variables (a and b),
+// so its Xoffset will be 2. Correspondingly, the "a, b = g()"
+// assignment's "blocking" entry will have two entries back to x's
+// assignment.
+//
+// Logically, initialization works by (1) taking all NotStarted
+// assignments, calculating their dependencies, and marking them
+// Pending; (2) adding all Pending assignments with Xoffset==0 to a
+// "ready" priority queue (ordered by variable declaration position);
+// and (3) iteratively processing the next Pending assignment from the
+// queue, decreasing the Xoffset of assignments it's blocking, and
+// adding them to the queue if decremented to 0.
+//
+// As an optimization, we actually apply each of these three steps for
+// each assignment. This yields the same order, but keeps queue size
+// down and thus also heap operation costs.
+
+// Static initialization phase.
+// These values are stored in two bits in Node.flags.
+const (
+ InitNotStarted = iota
+ InitDone
+ InitPending
+)
+
+type InitOrder struct {
+ // blocking maps initialization assignments to the assignments
+ // that depend on it.
+ blocking map[*Node][]*Node
+
+ // ready is the queue of Pending initialization assignments
+ // that are ready for initialization.
+ ready declOrder
+}
+
+// initOrder computes initialization order for a list l of
+// package-level declarations (in declaration order) and outputs the
+// corresponding list of statements to include in the init() function
+// body.
+func initOrder(l []*Node) []*Node {
+ s := InitSchedule{
+ initplans: make(map[*Node]*InitPlan),
+ inittemps: make(map[*Node]*Node),
+ }
+ o := InitOrder{
+ blocking: make(map[*Node][]*Node),
+ }
+
+ // Process all package-level assignment in declaration order.
+ for _, n := range l {
+ switch n.Op {
+ case OAS, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ o.processAssign(n)
+ o.flushReady(s.staticInit)
+ case ODCLCONST, ODCLFUNC, ODCLTYPE:
+ // nop
+ default:
+ Fatalf("unexpected package-level statement: %v", n)
+ }
+ }
+
+ // Check that all assignments are now Done; if not, there must
+ // have been a dependency cycle.
+ for _, n := range l {
+ switch n.Op {
+ case OAS, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ if n.Initorder() != InitDone {
+ // If there have already been errors
+ // printed, those errors may have
+ // confused us and there might not be
+ // a loop. Let the user fix those
+ // first.
+ if nerrors > 0 {
+ errorexit()
+ }
+
+ findInitLoopAndExit(firstLHS(n), new([]*Node), make(map[*Node]bool))
+ Fatalf("initialization unfinished, but failed to identify loop")
+ }
+ }
+ }
+
+ // Invariant consistency check. If this is non-zero, then we
+ // should have found a cycle above.
+ if len(o.blocking) != 0 {
+ Fatalf("expected empty map: %v", o.blocking)
+ }
+
+ return s.out
+}
+
+func (o *InitOrder) processAssign(n *Node) {
+ if n.Initorder() != InitNotStarted || n.Xoffset != BADWIDTH {
+ Fatalf("unexpected state: %v, %v, %v", n, n.Initorder(), n.Xoffset)
+ }
+
+ n.SetInitorder(InitPending)
+ n.Xoffset = 0
+
+ // Compute number of variable dependencies and build the
+ // inverse dependency ("blocking") graph.
+ for dep := range collectDeps(n, true) {
+ defn := dep.Name.Defn
+ // Skip dependencies on functions (PFUNC) and
+ // variables already initialized (InitDone).
+ if dep.Class() != PEXTERN || defn.Initorder() == InitDone {
+ continue
+ }
+ n.Xoffset++
+ o.blocking[defn] = append(o.blocking[defn], n)
+ }
+
+ if n.Xoffset == 0 {
+ heap.Push(&o.ready, n)
+ }
+}
+
+// flushReady repeatedly applies initialize to the earliest (in
+// declaration order) assignment ready for initialization and updates
+// the inverse dependency ("blocking") graph.
+func (o *InitOrder) flushReady(initialize func(*Node)) {
+ for o.ready.Len() != 0 {
+ n := heap.Pop(&o.ready).(*Node)
+ if n.Initorder() != InitPending || n.Xoffset != 0 {
+ Fatalf("unexpected state: %v, %v, %v", n, n.Initorder(), n.Xoffset)
+ }
+
+ initialize(n)
+ n.SetInitorder(InitDone)
+ n.Xoffset = BADWIDTH
+
+ blocked := o.blocking[n]
+ delete(o.blocking, n)
+
+ for _, m := range blocked {
+ m.Xoffset--
+ if m.Xoffset == 0 {
+ heap.Push(&o.ready, m)
+ }
+ }
+ }
+}
+
+// findInitLoopAndExit searches for an initialization loop involving variable
+// or function n. If one is found, it reports the loop as an error and exits.
+//
+// path points to a slice used for tracking the sequence of
+// variables/functions visited. Using a pointer to a slice allows the
+// slice capacity to grow and limit reallocations.
+func findInitLoopAndExit(n *Node, path *[]*Node, ok map[*Node]bool) {
+ for i, x := range *path {
+ if x == n {
+ reportInitLoopAndExit((*path)[i:])
+ return
+ }
+ }
+
+ // There might be multiple loops involving n; by sorting
+ // references, we deterministically pick the one reported.
+ refers := collectDeps(n.Name.Defn, false).Sorted(func(ni, nj *Node) bool {
+ return ni.Pos.Before(nj.Pos)
+ })
+
+ *path = append(*path, n)
+ for _, ref := range refers {
+ // Short-circuit variables that were initialized.
+ if ref.Class() == PEXTERN && ref.Name.Defn.Initorder() == InitDone || ok[ref] {
+ continue
+ }
+ findInitLoopAndExit(ref, path, ok)
+ }
+
+ // n is not involved in a cycle.
+ // Record that fact to avoid checking it again when reached another way,
+ // or else this traversal will take exponential time traversing all paths
+ // through the part of the package's call graph implicated in the cycle.
+ ok[n] = true
+
+ *path = (*path)[:len(*path)-1]
+}
+
+// reportInitLoopAndExit reports and initialization loop as an error
+// and exits. However, if l is not actually an initialization loop, it
+// simply returns instead.
+func reportInitLoopAndExit(l []*Node) {
+ // Rotate loop so that the earliest variable declaration is at
+ // the start.
+ i := -1
+ for j, n := range l {
+ if n.Class() == PEXTERN && (i == -1 || n.Pos.Before(l[i].Pos)) {
+ i = j
+ }
+ }
+ if i == -1 {
+ // False positive: loop only involves recursive
+ // functions. Return so that findInitLoop can continue
+ // searching.
+ return
+ }
+ l = append(l[i:], l[:i]...)
+
+ // TODO(mdempsky): Method values are printed as "T.m-fm"
+ // rather than "T.m". Figure out how to avoid that.
+
+ var msg bytes.Buffer
+ fmt.Fprintf(&msg, "initialization loop:\n")
+ for _, n := range l {
+ fmt.Fprintf(&msg, "\t%v: %v refers to\n", n.Line(), n)
+ }
+ fmt.Fprintf(&msg, "\t%v: %v", l[0].Line(), l[0])
+
+ yyerrorl(l[0].Pos, msg.String())
+ errorexit()
+}
+
+// collectDeps returns all of the package-level functions and
+// variables that declaration n depends on. If transitive is true,
+// then it also includes the transitive dependencies of any depended
+// upon functions (but not variables).
+func collectDeps(n *Node, transitive bool) NodeSet {
+ d := initDeps{transitive: transitive}
+ switch n.Op {
+ case OAS:
+ d.inspect(n.Right)
+ case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+ d.inspect(n.Right)
+ case ODCLFUNC:
+ d.inspectList(n.Nbody)
+ default:
+ Fatalf("unexpected Op: %v", n.Op)
+ }
+ return d.seen
+}
+
+type initDeps struct {
+ transitive bool
+ seen NodeSet
+}
+
+func (d *initDeps) inspect(n *Node) { inspect(n, d.visit) }
+func (d *initDeps) inspectList(l Nodes) { inspectList(l, d.visit) }
+
+// visit calls foundDep on any package-level functions or variables
+// referenced by n, if any.
+func (d *initDeps) visit(n *Node) bool {
+ switch n.Op {
+ case ONAME:
+ if n.isMethodExpression() {
+ d.foundDep(asNode(n.Type.FuncType().Nname))
+ return false
+ }
+
+ switch n.Class() {
+ case PEXTERN, PFUNC:
+ d.foundDep(n)
+ }
+
+ case OCLOSURE:
+ d.inspectList(n.Func.Closure.Nbody)
+
+ case ODOTMETH, OCALLPART:
+ d.foundDep(asNode(n.Type.FuncType().Nname))
+ }
+
+ return true
+}
+
+// foundDep records that we've found a dependency on n by adding it to
+// seen.
+func (d *initDeps) foundDep(n *Node) {
+ // Can happen with method expressions involving interface
+ // types; e.g., fixedbugs/issue4495.go.
+ if n == nil {
+ return
+ }
+
+ // Names without definitions aren't interesting as far as
+ // initialization ordering goes.
+ if n.Name.Defn == nil {
+ return
+ }
+
+ if d.seen.Has(n) {
+ return
+ }
+ d.seen.Add(n)
+ if d.transitive && n.Class() == PFUNC {
+ d.inspectList(n.Name.Defn.Nbody)
+ }
+}
+
+// declOrder implements heap.Interface, ordering assignment statements
+// by the position of their first LHS expression.
+//
+// N.B., the Pos of the first LHS expression is used because because
+// an OAS node's Pos may not be unique. For example, given the
+// declaration "var a, b = f(), g()", "a" must be ordered before "b",
+// but both OAS nodes use the "=" token's position as their Pos.
+type declOrder []*Node
+
+func (s declOrder) Len() int { return len(s) }
+func (s declOrder) Less(i, j int) bool { return firstLHS(s[i]).Pos.Before(firstLHS(s[j]).Pos) }
+func (s declOrder) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func (s *declOrder) Push(x interface{}) { *s = append(*s, x.(*Node)) }
+func (s *declOrder) Pop() interface{} {
+ n := (*s)[len(*s)-1]
+ *s = (*s)[:len(*s)-1]
+ return n
+}
+
+// firstLHS returns the first expression on the left-hand side of
+// assignment n.
+func firstLHS(n *Node) *Node {
+ switch n.Op {
+ case OAS:
+ return n.Left
+ case OAS2DOTTYPE, OAS2FUNC, OAS2RECV, OAS2MAPR:
+ return n.List.First()
+ }
+
+ Fatalf("unexpected Op: %v", n.Op)
+ return nil
+}
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
new file mode 100644
index 0000000..a8cc010
--- /dev/null
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -0,0 +1,1507 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// The inlining facility makes 2 passes: first caninl determines which
+// functions are suitable for inlining, and for those that are it
+// saves a copy of the body. Then inlcalls walks each function body to
+// expand calls to inlinable functions.
+//
+// The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
+// making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
+// are not supported.
+// 0: disabled
+// 1: 80-nodes leaf functions, oneliners, panic, lazy typechecking (default)
+// 2: (unassigned)
+// 3: (unassigned)
+// 4: allow non-leaf functions
+//
+// At some point this may get another default and become switch-offable with -N.
+//
+// The -d typcheckinl flag enables early typechecking of all imported bodies,
+// which is useful to flush out bugs.
+//
+// The Debug.m flag enables diagnostic output. a single -m is useful for verifying
+// which calls get inlined or not, more is for debugging, and may go away at any point.
+
+package gc
+
+import (
+ "cmd/compile/internal/logopt"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+ "fmt"
+ "strings"
+)
+
+// Inlining budget parameters, gathered in one place
+const (
+ inlineMaxBudget = 80
+ inlineExtraAppendCost = 0
+ // default is to inline if there's at most one call. -l=4 overrides this by using 1 instead.
+ inlineExtraCallCost = 57 // 57 was benchmarked to provided most benefit with no bad surprises; see https://github.com/golang/go/issues/19348#issuecomment-439370742
+ inlineExtraPanicCost = 1 // do not penalize inlining panics.
+ inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
+
+ inlineBigFunctionNodes = 5000 // Functions with this many nodes are considered "big".
+ inlineBigFunctionMaxCost = 20 // Max cost of inlinee when inlining into a "big" function.
+)
+
+// 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) *types.Pkg {
+ if fn.IsMethod() {
+ // method
+ rcvr := fn.Type.Recv().Type
+
+ if rcvr.IsPtr() {
+ rcvr = rcvr.Elem()
+ }
+ if rcvr.Sym == nil {
+ Fatalf("receiver with no sym: [%v] %L (%v)", fn.Sym, fn, rcvr)
+ }
+ return rcvr.Sym.Pkg
+ }
+
+ // non-method
+ return fn.Sym.Pkg
+}
+
+// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
+// because they're a copy of an already checked body.
+func typecheckinl(fn *Node) {
+ lno := setlineno(fn)
+
+ expandInline(fn)
+
+ // typecheckinl is only for imported functions;
+ // their bodies may refer to unsafe as long as the package
+ // was marked safe during import (which was checked then).
+ // the ->inl of a local function has been typechecked before caninl copied it.
+ pkg := fnpkg(fn)
+
+ if pkg == localpkg || pkg == nil {
+ return // typecheckinl on local function
+ }
+
+ if Debug.m > 2 || Debug_export != 0 {
+ fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
+ }
+
+ savefn := Curfn
+ Curfn = fn
+ typecheckslice(fn.Func.Inl.Body, ctxStmt)
+ Curfn = savefn
+
+ // During expandInline (which imports fn.Func.Inl.Body),
+ // declarations are added to fn.Func.Dcl by funcHdr(). Move them
+ // to fn.Func.Inl.Dcl for consistency with how local functions
+ // behave. (Append because typecheckinl may be called multiple
+ // times.)
+ fn.Func.Inl.Dcl = append(fn.Func.Inl.Dcl, fn.Func.Dcl...)
+ fn.Func.Dcl = nil
+
+ lineno = lno
+}
+
+// Caninl determines whether fn is inlineable.
+// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
+// fn and ->nbody will already have been typechecked.
+func caninl(fn *Node) {
+ if fn.Op != ODCLFUNC {
+ Fatalf("caninl %v", fn)
+ }
+ if fn.Func.Nname == nil {
+ Fatalf("caninl no nname %+v", fn)
+ }
+
+ var reason string // reason, if any, that the function was not inlined
+ if Debug.m > 1 || logopt.Enabled() {
+ defer func() {
+ if reason != "" {
+ if Debug.m > 1 {
+ fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
+ }
+ if logopt.Enabled() {
+ logopt.LogOpt(fn.Pos, "cannotInlineFunction", "inline", fn.funcname(), reason)
+ }
+ }
+ }()
+ }
+
+ // If marked "go:noinline", don't inline
+ if fn.Func.Pragma&Noinline != 0 {
+ reason = "marked go:noinline"
+ return
+ }
+
+ // If marked "go:norace" and -race compilation, don't inline.
+ if flag_race && fn.Func.Pragma&Norace != 0 {
+ reason = "marked go:norace with -race compilation"
+ return
+ }
+
+ // If marked "go:nocheckptr" and -d checkptr compilation, don't inline.
+ if Debug_checkptr != 0 && fn.Func.Pragma&NoCheckPtr != 0 {
+ reason = "marked go:nocheckptr"
+ return
+ }
+
+ // If marked "go:cgo_unsafe_args", don't inline, since the
+ // function makes assumptions about its argument frame layout.
+ if fn.Func.Pragma&CgoUnsafeArgs != 0 {
+ reason = "marked go:cgo_unsafe_args"
+ return
+ }
+
+ // If marked as "go:uintptrescapes", don't inline, since the
+ // escape information is lost during inlining.
+ if fn.Func.Pragma&UintptrEscapes != 0 {
+ reason = "marked as having an escaping uintptr argument"
+ return
+ }
+
+ // The nowritebarrierrec checker currently works at function
+ // granularity, so inlining yeswritebarrierrec functions can
+ // confuse it (#22342). As a workaround, disallow inlining
+ // them for now.
+ if fn.Func.Pragma&Yeswritebarrierrec != 0 {
+ reason = "marked go:yeswritebarrierrec"
+ return
+ }
+
+ // If fn has no body (is defined outside of Go), cannot inline it.
+ if fn.Nbody.Len() == 0 {
+ reason = "no function body"
+ return
+ }
+
+ if fn.Typecheck() == 0 {
+ Fatalf("caninl on non-typechecked function %v", fn)
+ }
+
+ n := fn.Func.Nname
+ if n.Func.InlinabilityChecked() {
+ return
+ }
+ defer n.Func.SetInlinabilityChecked(true)
+
+ cc := int32(inlineExtraCallCost)
+ if Debug.l == 4 {
+ cc = 1 // this appears to yield better performance than 0.
+ }
+
+ // At this point in the game the function we're looking at may
+ // have "stale" autos, vars that still appear in the Dcl list, but
+ // which no longer have any uses in the function body (due to
+ // elimination by deadcode). We'd like to exclude these dead vars
+ // when creating the "Inline.Dcl" field below; to accomplish this,
+ // the hairyVisitor below builds up a map of used/referenced
+ // locals, and we use this map to produce a pruned Inline.Dcl
+ // list. See issue 25249 for more context.
+
+ visitor := hairyVisitor{
+ budget: inlineMaxBudget,
+ extraCallCost: cc,
+ usedLocals: make(map[*Node]bool),
+ }
+ if visitor.visitList(fn.Nbody) {
+ reason = visitor.reason
+ return
+ }
+ if visitor.budget < 0 {
+ reason = fmt.Sprintf("function too complex: cost %d exceeds budget %d", inlineMaxBudget-visitor.budget, inlineMaxBudget)
+ return
+ }
+
+ n.Func.Inl = &Inline{
+ Cost: inlineMaxBudget - visitor.budget,
+ Dcl: inlcopylist(pruneUnusedAutos(n.Name.Defn.Func.Dcl, &visitor)),
+ Body: inlcopylist(fn.Nbody.Slice()),
+ }
+
+ // hack, TODO, check for better way to link method nodes back to the thing with the ->inl
+ // this is so export can find the body of a method
+ fn.Type.FuncType().Nname = asTypesNode(n)
+
+ if Debug.m > 1 {
+ fmt.Printf("%v: can inline %#v with cost %d as: %#v { %#v }\n", fn.Line(), n, inlineMaxBudget-visitor.budget, fn.Type, asNodes(n.Func.Inl.Body))
+ } else if Debug.m != 0 {
+ fmt.Printf("%v: can inline %v\n", fn.Line(), n)
+ }
+ if logopt.Enabled() {
+ logopt.LogOpt(fn.Pos, "canInlineFunction", "inline", fn.funcname(), fmt.Sprintf("cost: %d", inlineMaxBudget-visitor.budget))
+ }
+}
+
+// inlFlood marks n's inline body for export and recursively ensures
+// all called functions are marked too.
+func inlFlood(n *Node) {
+ if n == nil {
+ return
+ }
+ if n.Op != ONAME || n.Class() != PFUNC {
+ Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op, n.Class())
+ }
+ if n.Func == nil {
+ Fatalf("inlFlood: missing Func on %v", n)
+ }
+ if n.Func.Inl == nil {
+ return
+ }
+
+ if n.Func.ExportInline() {
+ return
+ }
+ n.Func.SetExportInline(true)
+
+ typecheckinl(n)
+
+ // Recursively identify all referenced functions for
+ // reexport. We want to include even non-called functions,
+ // because after inlining they might be callable.
+ inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
+ switch n.Op {
+ case ONAME:
+ switch n.Class() {
+ case PFUNC:
+ if n.isMethodExpression() {
+ inlFlood(asNode(n.Type.Nname()))
+ } else {
+ inlFlood(n)
+ exportsym(n)
+ }
+ case PEXTERN:
+ exportsym(n)
+ }
+
+ case ODOTMETH:
+ fn := asNode(n.Type.Nname())
+ inlFlood(fn)
+
+ case OCALLPART:
+ // Okay, because we don't yet inline indirect
+ // calls to method values.
+ case OCLOSURE:
+ // If the closure is inlinable, we'll need to
+ // flood it too. But today we don't support
+ // inlining functions that contain closures.
+ //
+ // When we do, we'll probably want:
+ // inlFlood(n.Func.Closure.Func.Nname)
+ Fatalf("unexpected closure in inlinable function")
+ }
+ return true
+ })
+}
+
+// hairyVisitor visits a function body to determine its inlining
+// hairiness and whether or not it can be inlined.
+type hairyVisitor struct {
+ budget int32
+ reason string
+ extraCallCost int32
+ usedLocals map[*Node]bool
+}
+
+// Look for anything we want to punt on.
+func (v *hairyVisitor) visitList(ll Nodes) bool {
+ for _, n := range ll.Slice() {
+ if v.visit(n) {
+ return true
+ }
+ }
+ return false
+}
+
+func (v *hairyVisitor) visit(n *Node) bool {
+ if n == nil {
+ return false
+ }
+
+ switch n.Op {
+ // Call is okay if inlinable and we have the budget for the body.
+ case OCALLFUNC:
+ // Functions that call runtime.getcaller{pc,sp} can not be inlined
+ // because getcaller{pc,sp} expect a pointer to the caller's first argument.
+ //
+ // runtime.throw is a "cheap call" like panic in normal code.
+ if n.Left.Op == ONAME && n.Left.Class() == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
+ fn := n.Left.Sym.Name
+ if fn == "getcallerpc" || fn == "getcallersp" {
+ v.reason = "call to " + fn
+ return true
+ }
+ if fn == "throw" {
+ v.budget -= inlineExtraThrowCost
+ break
+ }
+ }
+
+ if isIntrinsicCall(n) {
+ // Treat like any other node.
+ break
+ }
+
+ if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
+ v.budget -= fn.Func.Inl.Cost
+ break
+ }
+
+ // Call cost for non-leaf inlining.
+ v.budget -= v.extraCallCost
+
+ // Call is okay if inlinable and we have the budget for the body.
+ case OCALLMETH:
+ t := n.Left.Type
+ if t == nil {
+ 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, t)
+ }
+ if isRuntimePkg(n.Left.Sym.Pkg) {
+ fn := n.Left.Sym.Name
+ if fn == "heapBits.nextArena" {
+ // Special case: explicitly allow
+ // mid-stack inlining of
+ // runtime.heapBits.next even though
+ // it calls slow-path
+ // runtime.heapBits.nextArena.
+ break
+ }
+ }
+ if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl != nil {
+ v.budget -= inlfn.Inl.Cost
+ break
+ }
+ // Call cost for non-leaf inlining.
+ v.budget -= v.extraCallCost
+
+ // Things that are too hairy, irrespective of the budget
+ case OCALL, OCALLINTER:
+ // Call cost for non-leaf inlining.
+ v.budget -= v.extraCallCost
+
+ case OPANIC:
+ v.budget -= inlineExtraPanicCost
+
+ case ORECOVER:
+ // recover matches the argument frame pointer to find
+ // the right panic value, so it needs an argument frame.
+ v.reason = "call to recover"
+ return true
+
+ case OCLOSURE,
+ ORANGE,
+ OSELECT,
+ OGO,
+ ODEFER,
+ ODCLTYPE, // can't print yet
+ ORETJMP:
+ v.reason = "unhandled op " + n.Op.String()
+ return true
+
+ case OAPPEND:
+ v.budget -= inlineExtraAppendCost
+
+ case ODCLCONST, OEMPTY, OFALL:
+ // These nodes don't produce code; omit from inlining budget.
+ return false
+
+ case OLABEL:
+ // TODO(mdempsky): Add support for inlining labeled control statements.
+ if n.labeledControl() != nil {
+ v.reason = "labeled control"
+ return true
+ }
+
+ case OBREAK, OCONTINUE:
+ if n.Sym != nil {
+ // Should have short-circuited due to labeledControl above.
+ Fatalf("unexpected labeled break/continue: %v", n)
+ }
+
+ case OIF:
+ if Isconst(n.Left, CTBOOL) {
+ // This if and the condition cost nothing.
+ return v.visitList(n.Ninit) || v.visitList(n.Nbody) ||
+ v.visitList(n.Rlist)
+ }
+
+ case ONAME:
+ if n.Class() == PAUTO {
+ v.usedLocals[n] = true
+ }
+
+ }
+
+ v.budget--
+
+ // When debugging, don't stop early, to get full cost of inlining this function
+ if v.budget < 0 && Debug.m < 2 && !logopt.Enabled() {
+ return true
+ }
+
+ return v.visit(n.Left) || v.visit(n.Right) ||
+ v.visitList(n.List) || v.visitList(n.Rlist) ||
+ v.visitList(n.Ninit) || v.visitList(n.Nbody)
+}
+
+// inlcopylist (together with inlcopy) recursively copies a list of nodes, except
+// that it keeps the same ONAME, OTYPE, and OLITERAL nodes. It is used for copying
+// the body and dcls of an inlineable function.
+func inlcopylist(ll []*Node) []*Node {
+ s := make([]*Node, 0, len(ll))
+ for _, n := range ll {
+ s = append(s, inlcopy(n))
+ }
+ return s
+}
+
+func inlcopy(n *Node) *Node {
+ if n == nil {
+ return nil
+ }
+
+ switch n.Op {
+ case ONAME, OTYPE, OLITERAL:
+ return n
+ }
+
+ m := n.copy()
+ if n.Op != OCALLPART && m.Func != nil {
+ Fatalf("unexpected Func: %v", m)
+ }
+ m.Left = inlcopy(n.Left)
+ m.Right = inlcopy(n.Right)
+ m.List.Set(inlcopylist(n.List.Slice()))
+ m.Rlist.Set(inlcopylist(n.Rlist.Slice()))
+ m.Ninit.Set(inlcopylist(n.Ninit.Slice()))
+ m.Nbody.Set(inlcopylist(n.Nbody.Slice()))
+
+ return m
+}
+
+func countNodes(n *Node) int {
+ if n == nil {
+ return 0
+ }
+ cnt := 1
+ cnt += countNodes(n.Left)
+ cnt += countNodes(n.Right)
+ for _, n1 := range n.Ninit.Slice() {
+ cnt += countNodes(n1)
+ }
+ for _, n1 := range n.Nbody.Slice() {
+ cnt += countNodes(n1)
+ }
+ for _, n1 := range n.List.Slice() {
+ cnt += countNodes(n1)
+ }
+ for _, n1 := range n.Rlist.Slice() {
+ cnt += countNodes(n1)
+ }
+ return cnt
+}
+
+// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
+// calls made to inlineable functions. This is the external entry point.
+func inlcalls(fn *Node) {
+ savefn := Curfn
+ Curfn = fn
+ maxCost := int32(inlineMaxBudget)
+ if countNodes(fn) >= inlineBigFunctionNodes {
+ maxCost = inlineBigFunctionMaxCost
+ }
+ // Map to keep track of functions that have been inlined at a particular
+ // call site, in order to stop inlining when we reach the beginning of a
+ // recursion cycle again. We don't inline immediately recursive functions,
+ // but allow inlining if there is a recursion cycle of many functions.
+ // Most likely, the inlining will stop before we even hit the beginning of
+ // the cycle again, but the map catches the unusual case.
+ inlMap := make(map[*Node]bool)
+ fn = inlnode(fn, maxCost, inlMap)
+ if fn != Curfn {
+ Fatalf("inlnode replaced curfn")
+ }
+ Curfn = savefn
+}
+
+// Turn an OINLCALL into a statement.
+func inlconv2stmt(n *Node) {
+ n.Op = OBLOCK
+
+ // n->ninit stays
+ n.List.Set(n.Nbody.Slice())
+
+ n.Nbody.Set(nil)
+ n.Rlist.Set(nil)
+}
+
+// Turn an OINLCALL into a single valued expression.
+// The result of inlconv2expr MUST be assigned back to n, e.g.
+// n.Left = inlconv2expr(n.Left)
+func inlconv2expr(n *Node) *Node {
+ r := n.Rlist.First()
+ return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
+}
+
+// Turn the rlist (with the return values) of the OINLCALL in
+// n into an expression list lumping the ninit and body
+// containing the inlined statements on the first list element so
+// order will be preserved Used in return, oas2func and call
+// statements.
+func inlconv2list(n *Node) []*Node {
+ if n.Op != OINLCALL || n.Rlist.Len() == 0 {
+ Fatalf("inlconv2list %+v\n", n)
+ }
+
+ s := n.Rlist.Slice()
+ s[0] = addinit(s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...))
+ return s
+}
+
+func inlnodelist(l Nodes, maxCost int32, inlMap map[*Node]bool) {
+ s := l.Slice()
+ for i := range s {
+ s[i] = inlnode(s[i], maxCost, inlMap)
+ }
+}
+
+// inlnode recurses over the tree to find inlineable calls, which will
+// be turned into OINLCALLs by mkinlcall. When the recursion comes
+// back up will examine left, right, list, rlist, ninit, ntest, nincr,
+// nbody and nelse and use one of the 4 inlconv/glue functions above
+// to turn the OINLCALL into an expression, a statement, or patch it
+// in to this nodes list or rlist as appropriate.
+// NOTE it makes no sense to pass the glue functions down the
+// recursion to the level where the OINLCALL gets created because they
+// have to edit /this/ n, so you'd have to push that one down as well,
+// but then you may as well do it here. so this is cleaner and
+// shorter and less complicated.
+// The result of inlnode MUST be assigned back to n, e.g.
+// n.Left = inlnode(n.Left)
+func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
+ if n == nil {
+ return n
+ }
+
+ switch n.Op {
+ case ODEFER, OGO:
+ switch n.Left.Op {
+ case OCALLFUNC, OCALLMETH:
+ n.Left.SetNoInline(true)
+ }
+
+ // TODO do them here (or earlier),
+ // so escape analysis can avoid more heapmoves.
+ case OCLOSURE:
+ return n
+ case OCALLMETH:
+ // Prevent inlining some reflect.Value methods when using checkptr,
+ // even when package reflect was compiled without it (#35073).
+ if s := n.Left.Sym; Debug_checkptr != 0 && isReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
+ return n
+ }
+ }
+
+ lno := setlineno(n)
+
+ inlnodelist(n.Ninit, maxCost, inlMap)
+ for _, n1 := range n.Ninit.Slice() {
+ if n1.Op == OINLCALL {
+ inlconv2stmt(n1)
+ }
+ }
+
+ n.Left = inlnode(n.Left, maxCost, inlMap)
+ if n.Left != nil && n.Left.Op == OINLCALL {
+ n.Left = inlconv2expr(n.Left)
+ }
+
+ n.Right = inlnode(n.Right, maxCost, inlMap)
+ if n.Right != nil && n.Right.Op == OINLCALL {
+ if n.Op == OFOR || n.Op == OFORUNTIL {
+ inlconv2stmt(n.Right)
+ } else if n.Op == OAS2FUNC {
+ n.Rlist.Set(inlconv2list(n.Right))
+ n.Right = nil
+ n.Op = OAS2
+ n.SetTypecheck(0)
+ n = typecheck(n, ctxStmt)
+ } else {
+ n.Right = inlconv2expr(n.Right)
+ }
+ }
+
+ inlnodelist(n.List, maxCost, inlMap)
+ if n.Op == OBLOCK {
+ for _, n2 := range n.List.Slice() {
+ if n2.Op == OINLCALL {
+ inlconv2stmt(n2)
+ }
+ }
+ } else {
+ s := n.List.Slice()
+ for i1, n1 := range s {
+ if n1 != nil && n1.Op == OINLCALL {
+ s[i1] = inlconv2expr(s[i1])
+ }
+ }
+ }
+
+ inlnodelist(n.Rlist, maxCost, inlMap)
+ s := n.Rlist.Slice()
+ for i1, n1 := range s {
+ if n1.Op == OINLCALL {
+ if n.Op == OIF {
+ inlconv2stmt(n1)
+ } else {
+ s[i1] = inlconv2expr(s[i1])
+ }
+ }
+ }
+
+ inlnodelist(n.Nbody, maxCost, inlMap)
+ for _, n := range n.Nbody.Slice() {
+ if n.Op == OINLCALL {
+ inlconv2stmt(n)
+ }
+ }
+
+ // with all the branches out of the way, it is now time to
+ // transmogrify this node itself unless inhibited by the
+ // switch at the top of this function.
+ switch n.Op {
+ case OCALLFUNC, OCALLMETH:
+ if n.NoInline() {
+ return n
+ }
+ }
+
+ switch n.Op {
+ case OCALLFUNC:
+ if Debug.m > 3 {
+ fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
+ }
+ if isIntrinsicCall(n) {
+ break
+ }
+ if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
+ n = mkinlcall(n, fn, maxCost, inlMap)
+ }
+
+ case OCALLMETH:
+ if Debug.m > 3 {
+ 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, n.Left)
+ }
+
+ if n.Left.Type.Nname() == nil {
+ Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
+ }
+
+ n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), maxCost, inlMap)
+ }
+
+ lineno = lno
+ return n
+}
+
+// inlCallee takes a function-typed expression and returns the underlying function ONAME
+// that it refers to if statically known. Otherwise, it returns nil.
+func inlCallee(fn *Node) *Node {
+ fn = staticValue(fn)
+ switch {
+ case fn.Op == ONAME && fn.Class() == PFUNC:
+ if fn.isMethodExpression() {
+ n := asNode(fn.Type.Nname())
+ // Check that receiver type matches fn.Left.
+ // TODO(mdempsky): Handle implicit dereference
+ // of pointer receiver argument?
+ if n == nil || !types.Identical(n.Type.Recv().Type, fn.Left.Type) {
+ return nil
+ }
+ return n
+ }
+ return fn
+ case fn.Op == OCLOSURE:
+ c := fn.Func.Closure
+ caninl(c)
+ return c.Func.Nname
+ }
+ return nil
+}
+
+func staticValue(n *Node) *Node {
+ for {
+ if n.Op == OCONVNOP {
+ n = n.Left
+ continue
+ }
+
+ n1 := staticValue1(n)
+ if n1 == nil {
+ return n
+ }
+ n = n1
+ }
+}
+
+// staticValue1 implements a simple SSA-like optimization. If n is a local variable
+// that is initialized and never reassigned, staticValue1 returns the initializer
+// expression. Otherwise, it returns nil.
+func staticValue1(n *Node) *Node {
+ if n.Op != ONAME || n.Class() != PAUTO || n.Name.Addrtaken() {
+ return nil
+ }
+
+ defn := n.Name.Defn
+ if defn == nil {
+ return nil
+ }
+
+ var rhs *Node
+FindRHS:
+ switch defn.Op {
+ case OAS:
+ rhs = defn.Right
+ case OAS2:
+ for i, lhs := range defn.List.Slice() {
+ if lhs == n {
+ rhs = defn.Rlist.Index(i)
+ break FindRHS
+ }
+ }
+ Fatalf("%v missing from LHS of %v", n, defn)
+ default:
+ return nil
+ }
+ if rhs == nil {
+ Fatalf("RHS is nil: %v", defn)
+ }
+
+ unsafe, _ := reassigned(n)
+ if unsafe {
+ return nil
+ }
+
+ return rhs
+}
+
+// reassigned takes an ONAME node, walks the function in which it is defined, and returns a boolean
+// indicating whether the name has any assignments other than its declaration.
+// The second return value is the first such assignment encountered in the walk, if any. It is mostly
+// useful for -m output documenting the reason for inhibited optimizations.
+// NB: global variables are always considered to be re-assigned.
+// TODO: handle initial declaration not including an assignment and followed by a single assignment?
+func reassigned(n *Node) (bool, *Node) {
+ if n.Op != ONAME {
+ Fatalf("reassigned %v", n)
+ }
+ // no way to reliably check for no-reassignment of globals, assume it can be
+ if n.Name.Curfn == nil {
+ return true, nil
+ }
+ f := n.Name.Curfn
+ // There just might be a good reason for this although this can be pretty surprising:
+ // local variables inside a closure have Curfn pointing to the OCLOSURE node instead
+ // of the corresponding ODCLFUNC.
+ // We need to walk the function body to check for reassignments so we follow the
+ // linkage to the ODCLFUNC node as that is where body is held.
+ if f.Op == OCLOSURE {
+ f = f.Func.Closure
+ }
+ v := reassignVisitor{name: n}
+ a := v.visitList(f.Nbody)
+ return a != nil, a
+}
+
+type reassignVisitor struct {
+ name *Node
+}
+
+func (v *reassignVisitor) visit(n *Node) *Node {
+ if n == nil {
+ return nil
+ }
+ switch n.Op {
+ case OAS, OSELRECV:
+ if n.Left == v.name && n != v.name.Name.Defn {
+ return n
+ }
+ case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
+ for _, p := range n.List.Slice() {
+ if p == v.name && n != v.name.Name.Defn {
+ return n
+ }
+ }
+ case OSELRECV2:
+ if (n.Left == v.name || n.List.First() == v.name) && n != v.name.Name.Defn {
+ return n
+ }
+ }
+ if a := v.visit(n.Left); a != nil {
+ return a
+ }
+ if a := v.visit(n.Right); a != nil {
+ return a
+ }
+ if a := v.visitList(n.List); a != nil {
+ return a
+ }
+ if a := v.visitList(n.Rlist); a != nil {
+ return a
+ }
+ if a := v.visitList(n.Ninit); a != nil {
+ return a
+ }
+ if a := v.visitList(n.Nbody); a != nil {
+ return a
+ }
+ return nil
+}
+
+func (v *reassignVisitor) visitList(l Nodes) *Node {
+ for _, n := range l.Slice() {
+ if a := v.visit(n); a != nil {
+ return a
+ }
+ }
+ return nil
+}
+
+func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
+ n := asNode(t.Nname)
+ if n == nil || n.isBlank() {
+ return nblank
+ }
+
+ inlvar := inlvars[n]
+ if inlvar == nil {
+ Fatalf("missing inlvar for %v", n)
+ }
+ as.Ninit.Append(nod(ODCL, inlvar, nil))
+ inlvar.Name.Defn = as
+ return inlvar
+}
+
+var inlgen int
+
+// If n is a call node (OCALLFUNC or OCALLMETH), and fn is an ONAME node for a
+// function with an inlinable body, return an OINLCALL node that can replace n.
+// The returned node's Ninit has the parameter assignments, the Nbody is the
+// inlined function body, and (List, Rlist) contain the (input, output)
+// parameters.
+// The result of mkinlcall MUST be assigned back to n, e.g.
+// n.Left = mkinlcall(n.Left, fn, isddd)
+func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
+ if fn.Func.Inl == nil {
+ if logopt.Enabled() {
+ logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
+ fmt.Sprintf("%s cannot be inlined", fn.pkgFuncName()))
+ }
+ return n
+ }
+ if fn.Func.Inl.Cost > maxCost {
+ // The inlined function body is too big. Typically we use this check to restrict
+ // inlining into very big functions. See issue 26546 and 17566.
+ if logopt.Enabled() {
+ logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
+ fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Func.Inl.Cost, fn.pkgFuncName(), maxCost))
+ }
+ return n
+ }
+
+ if fn == Curfn || fn.Name.Defn == Curfn {
+ // Can't recursively inline a function into itself.
+ if logopt.Enabled() {
+ logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", Curfn.funcname()))
+ }
+ return n
+ }
+
+ if instrumenting && isRuntimePkg(fn.Sym.Pkg) {
+ // Runtime package must not be instrumented.
+ // Instrument skips runtime package. However, some runtime code can be
+ // inlined into other packages and instrumented there. To avoid this,
+ // we disable inlining of runtime functions when instrumenting.
+ // The example that we observed is inlining of LockOSThread,
+ // which lead to false race reports on m contents.
+ return n
+ }
+
+ if inlMap[fn] {
+ if Debug.m > 1 {
+ fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", n.Line(), fn, Curfn.funcname())
+ }
+ return n
+ }
+ inlMap[fn] = true
+ defer func() {
+ inlMap[fn] = false
+ }()
+ if Debug_typecheckinl == 0 {
+ typecheckinl(fn)
+ }
+
+ // We have a function node, and it has an inlineable body.
+ if Debug.m > 1 {
+ fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
+ } else if Debug.m != 0 {
+ fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
+ }
+ if Debug.m > 2 {
+ fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
+ }
+
+ if ssaDump != "" && ssaDump == Curfn.funcname() {
+ ssaDumpInlined = append(ssaDumpInlined, fn)
+ }
+
+ ninit := n.Ninit
+
+ // For normal function calls, the function callee expression
+ // may contain side effects (e.g., added by addinit during
+ // inlconv2expr or inlconv2list). Make sure to preserve these,
+ // if necessary (#42703).
+ if n.Op == OCALLFUNC {
+ callee := n.Left
+ for callee.Op == OCONVNOP {
+ ninit.AppendNodes(&callee.Ninit)
+ callee = callee.Left
+ }
+ if callee.Op != ONAME && callee.Op != OCLOSURE {
+ Fatalf("unexpected callee expression: %v", callee)
+ }
+ }
+
+ // Make temp names to use instead of the originals.
+ inlvars := make(map[*Node]*Node)
+
+ // record formals/locals for later post-processing
+ var inlfvars []*Node
+
+ // Handle captured variables when inlining closures.
+ if fn.Name.Defn != nil {
+ if c := fn.Name.Defn.Func.Closure; c != nil {
+ for _, v := range c.Func.Closure.Func.Cvars.Slice() {
+ if v.Op == OXXX {
+ continue
+ }
+
+ o := v.Name.Param.Outer
+ // make sure the outer param matches the inlining location
+ // NB: if we enabled inlining of functions containing OCLOSURE or refined
+ // the reassigned check via some sort of copy propagation this would most
+ // likely need to be changed to a loop to walk up to the correct Param
+ if o == nil || (o.Name.Curfn != Curfn && o.Name.Curfn.Func.Closure != Curfn) {
+ Fatalf("%v: unresolvable capture %v %v\n", n.Line(), fn, v)
+ }
+
+ if v.Name.Byval() {
+ iv := typecheck(inlvar(v), ctxExpr)
+ ninit.Append(nod(ODCL, iv, nil))
+ ninit.Append(typecheck(nod(OAS, iv, o), ctxStmt))
+ inlvars[v] = iv
+ } else {
+ addr := newname(lookup("&" + v.Sym.Name))
+ addr.Type = types.NewPtr(v.Type)
+ ia := typecheck(inlvar(addr), ctxExpr)
+ ninit.Append(nod(ODCL, ia, nil))
+ ninit.Append(typecheck(nod(OAS, ia, nod(OADDR, o, nil)), ctxStmt))
+ inlvars[addr] = ia
+
+ // When capturing by reference, all occurrence of the captured var
+ // must be substituted with dereference of the temporary address
+ inlvars[v] = typecheck(nod(ODEREF, ia, nil), ctxExpr)
+ }
+ }
+ }
+ }
+
+ for _, ln := range fn.Func.Inl.Dcl {
+ if ln.Op != ONAME {
+ continue
+ }
+ if ln.Class() == PPARAMOUT { // return values handled below.
+ continue
+ }
+ if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
+ // TODO(mdempsky): Remove once I'm confident
+ // this never actually happens. We currently
+ // perform inlining before escape analysis, so
+ // nothing should have moved to the heap yet.
+ Fatalf("impossible: %v", ln)
+ }
+ inlf := typecheck(inlvar(ln), ctxExpr)
+ inlvars[ln] = inlf
+ if genDwarfInline > 0 {
+ if ln.Class() == PPARAM {
+ inlf.Name.SetInlFormal(true)
+ } else {
+ inlf.Name.SetInlLocal(true)
+ }
+ inlf.Pos = ln.Pos
+ inlfvars = append(inlfvars, inlf)
+ }
+ }
+
+ // We can delay declaring+initializing result parameters if:
+ // (1) there's exactly one "return" statement in the inlined function;
+ // (2) it's not an empty return statement (#44355); and
+ // (3) the result parameters aren't named.
+ delayretvars := true
+
+ nreturns := 0
+ inspectList(asNodes(fn.Func.Inl.Body), func(n *Node) bool {
+ if n != nil && n.Op == ORETURN {
+ nreturns++
+ if n.List.Len() == 0 {
+ delayretvars = false // empty return statement (case 2)
+ }
+ }
+ return true
+ })
+
+ if nreturns != 1 {
+ delayretvars = false // not exactly one return statement (case 1)
+ }
+
+ // temporaries for return values.
+ var retvars []*Node
+ for i, t := range fn.Type.Results().Fields().Slice() {
+ var m *Node
+ if n := asNode(t.Nname); n != nil && !n.isBlank() && !strings.HasPrefix(n.Sym.Name, "~r") {
+ m = inlvar(n)
+ m = typecheck(m, ctxExpr)
+ inlvars[n] = m
+ delayretvars = false // found a named result parameter (case 3)
+ } else {
+ // anonymous return values, synthesize names for use in assignment that replaces return
+ m = retvar(t, i)
+ }
+
+ if genDwarfInline > 0 {
+ // Don't update the src.Pos on a return variable if it
+ // was manufactured by the inliner (e.g. "~R2"); such vars
+ // were not part of the original callee.
+ if !strings.HasPrefix(m.Sym.Name, "~R") {
+ m.Name.SetInlFormal(true)
+ m.Pos = t.Pos
+ inlfvars = append(inlfvars, m)
+ }
+ }
+
+ retvars = append(retvars, m)
+ }
+
+ // Assign arguments to the parameters' temp names.
+ as := nod(OAS2, nil, nil)
+ as.SetColas(true)
+ if n.Op == OCALLMETH {
+ if n.Left.Left == nil {
+ Fatalf("method call without receiver: %+v", n)
+ }
+ as.Rlist.Append(n.Left.Left)
+ }
+ as.Rlist.Append(n.List.Slice()...)
+
+ // For non-dotted calls to variadic functions, we assign the
+ // variadic parameter's temp name separately.
+ var vas *Node
+
+ if recv := fn.Type.Recv(); recv != nil {
+ as.List.Append(inlParam(recv, as, inlvars))
+ }
+ for _, param := range fn.Type.Params().Fields().Slice() {
+ // For ordinary parameters or variadic parameters in
+ // dotted calls, just add the variable to the
+ // assignment list, and we're done.
+ if !param.IsDDD() || n.IsDDD() {
+ as.List.Append(inlParam(param, as, inlvars))
+ continue
+ }
+
+ // Otherwise, we need to collect the remaining values
+ // to pass as a slice.
+
+ x := as.List.Len()
+ for as.List.Len() < as.Rlist.Len() {
+ as.List.Append(argvar(param.Type, as.List.Len()))
+ }
+ varargs := as.List.Slice()[x:]
+
+ vas = nod(OAS, nil, nil)
+ vas.Left = inlParam(param, vas, inlvars)
+ if len(varargs) == 0 {
+ vas.Right = nodnil()
+ vas.Right.Type = param.Type
+ } else {
+ vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
+ vas.Right.List.Set(varargs)
+ }
+ }
+
+ if as.Rlist.Len() != 0 {
+ as = typecheck(as, ctxStmt)
+ ninit.Append(as)
+ }
+
+ if vas != nil {
+ vas = typecheck(vas, ctxStmt)
+ ninit.Append(vas)
+ }
+
+ if !delayretvars {
+ // Zero the return parameters.
+ for _, n := range retvars {
+ ninit.Append(nod(ODCL, n, nil))
+ ras := nod(OAS, n, nil)
+ ras = typecheck(ras, ctxStmt)
+ ninit.Append(ras)
+ }
+ }
+
+ retlabel := autolabel(".i")
+
+ inlgen++
+
+ parent := -1
+ if b := Ctxt.PosTable.Pos(n.Pos).Base(); b != nil {
+ parent = b.InliningIndex()
+ }
+ newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
+
+ // Add an inline mark just before the inlined body.
+ // This mark is inline in the code so that it's a reasonable spot
+ // to put a breakpoint. Not sure if that's really necessary or not
+ // (in which case it could go at the end of the function instead).
+ // Note issue 28603.
+ inlMark := nod(OINLMARK, nil, nil)
+ inlMark.Pos = n.Pos.WithIsStmt()
+ inlMark.Xoffset = int64(newIndex)
+ ninit.Append(inlMark)
+
+ if genDwarfInline > 0 {
+ if !fn.Sym.Linksym().WasInlined() {
+ Ctxt.DwFixups.SetPrecursorFunc(fn.Sym.Linksym(), fn)
+ fn.Sym.Linksym().Set(obj.AttrWasInlined, true)
+ }
+ }
+
+ subst := inlsubst{
+ retlabel: retlabel,
+ retvars: retvars,
+ delayretvars: delayretvars,
+ inlvars: inlvars,
+ bases: make(map[*src.PosBase]*src.PosBase),
+ newInlIndex: newIndex,
+ }
+
+ body := subst.list(asNodes(fn.Func.Inl.Body))
+
+ lab := nodSym(OLABEL, nil, retlabel)
+ body = append(body, lab)
+
+ typecheckslice(body, ctxStmt)
+
+ if genDwarfInline > 0 {
+ for _, v := range inlfvars {
+ v.Pos = subst.updatedPos(v.Pos)
+ }
+ }
+
+ //dumplist("ninit post", ninit);
+
+ call := nod(OINLCALL, nil, nil)
+ call.Ninit.Set(ninit.Slice())
+ call.Nbody.Set(body)
+ call.Rlist.Set(retvars)
+ call.Type = n.Type
+ call.SetTypecheck(1)
+
+ // transitive inlining
+ // might be nice to do this before exporting the body,
+ // but can't emit the body with inlining expanded.
+ // instead we emit the things that the body needs
+ // and each use must redo the inlining.
+ // luckily these are small.
+ inlnodelist(call.Nbody, maxCost, inlMap)
+ for _, n := range call.Nbody.Slice() {
+ if n.Op == OINLCALL {
+ inlconv2stmt(n)
+ }
+ }
+
+ if Debug.m > 2 {
+ fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
+ }
+
+ return call
+}
+
+// Every time we expand a function we generate a new set of tmpnames,
+// PAUTO's in the calling functions, and link them off of the
+// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
+func inlvar(var_ *Node) *Node {
+ if Debug.m > 3 {
+ fmt.Printf("inlvar %+v\n", var_)
+ }
+
+ n := newname(var_.Sym)
+ n.Type = var_.Type
+ n.SetClass(PAUTO)
+ n.Name.SetUsed(true)
+ n.Name.Curfn = Curfn // the calling function, not the called one
+ n.Name.SetAddrtaken(var_.Name.Addrtaken())
+
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+ return n
+}
+
+// Synthesize a variable to store the inlined function's results in.
+func retvar(t *types.Field, i int) *Node {
+ n := newname(lookupN("~R", i))
+ n.Type = t.Type
+ n.SetClass(PAUTO)
+ n.Name.SetUsed(true)
+ n.Name.Curfn = Curfn // the calling function, not the called one
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+ return n
+}
+
+// Synthesize a variable to store the inlined function's arguments
+// when they come from a multiple return call.
+func argvar(t *types.Type, i int) *Node {
+ n := newname(lookupN("~arg", i))
+ n.Type = t.Elem()
+ n.SetClass(PAUTO)
+ n.Name.SetUsed(true)
+ n.Name.Curfn = Curfn // the calling function, not the called one
+ Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+ return n
+}
+
+// The inlsubst type implements the actual inlining of a single
+// function call.
+type inlsubst struct {
+ // Target of the goto substituted in place of a return.
+ retlabel *types.Sym
+
+ // Temporary result variables.
+ retvars []*Node
+
+ // Whether result variables should be initialized at the
+ // "return" statement.
+ delayretvars bool
+
+ inlvars map[*Node]*Node
+
+ // bases maps from original PosBase to PosBase with an extra
+ // inlined call frame.
+ bases map[*src.PosBase]*src.PosBase
+
+ // newInlIndex is the index of the inlined call frame to
+ // insert for inlined nodes.
+ newInlIndex int
+}
+
+// list inlines a list of nodes.
+func (subst *inlsubst) list(ll Nodes) []*Node {
+ s := make([]*Node, 0, ll.Len())
+ for _, n := range ll.Slice() {
+ s = append(s, subst.node(n))
+ }
+ return s
+}
+
+// node recursively copies a node from the saved pristine body of the
+// inlined function, substituting references to input/output
+// parameters with ones to the tmpnames, and substituting returns with
+// assignments to the output.
+func (subst *inlsubst) node(n *Node) *Node {
+ if n == nil {
+ return nil
+ }
+
+ switch n.Op {
+ case ONAME:
+ if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
+ if Debug.m > 2 {
+ fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
+ }
+ return inlvar
+ }
+
+ if Debug.m > 2 {
+ fmt.Printf("not substituting name %+v\n", n)
+ }
+ return n
+
+ case OLITERAL, OTYPE:
+ // If n is a named constant or type, we can continue
+ // using it in the inline copy. Otherwise, make a copy
+ // so we can update the line number.
+ if n.Sym != nil {
+ return n
+ }
+
+ // Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
+
+ // dump("Return before substitution", n);
+ case ORETURN:
+ m := nodSym(OGOTO, nil, subst.retlabel)
+ m.Ninit.Set(subst.list(n.Ninit))
+
+ if len(subst.retvars) != 0 && n.List.Len() != 0 {
+ as := nod(OAS2, nil, nil)
+
+ // Make a shallow copy of retvars.
+ // Otherwise OINLCALL.Rlist will be the same list,
+ // and later walk and typecheck may clobber it.
+ for _, n := range subst.retvars {
+ as.List.Append(n)
+ }
+ as.Rlist.Set(subst.list(n.List))
+
+ if subst.delayretvars {
+ for _, n := range as.List.Slice() {
+ as.Ninit.Append(nod(ODCL, n, nil))
+ n.Name.Defn = as
+ }
+ }
+
+ as = typecheck(as, ctxStmt)
+ m.Ninit.Append(as)
+ }
+
+ typecheckslice(m.Ninit.Slice(), ctxStmt)
+ m = typecheck(m, ctxStmt)
+
+ // dump("Return after substitution", m);
+ return m
+
+ case OGOTO, OLABEL:
+ m := n.copy()
+ m.Pos = subst.updatedPos(m.Pos)
+ m.Ninit.Set(nil)
+ p := fmt.Sprintf("%s·%d", n.Sym.Name, inlgen)
+ m.Sym = lookup(p)
+
+ return m
+ }
+
+ m := n.copy()
+ m.Pos = subst.updatedPos(m.Pos)
+ m.Ninit.Set(nil)
+
+ if n.Op == OCLOSURE {
+ Fatalf("cannot inline function containing closure: %+v", n)
+ }
+
+ m.Left = subst.node(n.Left)
+ m.Right = subst.node(n.Right)
+ m.List.Set(subst.list(n.List))
+ m.Rlist.Set(subst.list(n.Rlist))
+ m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
+ m.Nbody.Set(subst.list(n.Nbody))
+
+ return m
+}
+
+func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
+ pos := Ctxt.PosTable.Pos(xpos)
+ oldbase := pos.Base() // can be nil
+ newbase := subst.bases[oldbase]
+ if newbase == nil {
+ newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
+ subst.bases[oldbase] = newbase
+ }
+ pos.SetBase(newbase)
+ return Ctxt.PosTable.XPos(pos)
+}
+
+func pruneUnusedAutos(ll []*Node, vis *hairyVisitor) []*Node {
+ s := make([]*Node, 0, len(ll))
+ for _, n := range ll {
+ if n.Class() == PAUTO {
+ if _, found := vis.usedLocals[n]; !found {
+ continue
+ }
+ }
+ s = append(s, n)
+ }
+ return s
+}
+
+// devirtualize replaces interface method calls within fn with direct
+// concrete-type method calls where applicable.
+func devirtualize(fn *Node) {
+ Curfn = fn
+ inspectList(fn.Nbody, func(n *Node) bool {
+ if n.Op == OCALLINTER {
+ devirtualizeCall(n)
+ }
+ return true
+ })
+}
+
+func devirtualizeCall(call *Node) {
+ recv := staticValue(call.Left.Left)
+ if recv.Op != OCONVIFACE {
+ return
+ }
+
+ typ := recv.Left.Type
+ if typ.IsInterface() {
+ return
+ }
+
+ x := nodl(call.Left.Pos, ODOTTYPE, call.Left.Left, nil)
+ x.Type = typ
+ x = nodlSym(call.Left.Pos, OXDOT, x, call.Left.Sym)
+ x = typecheck(x, ctxExpr|ctxCallee)
+ switch x.Op {
+ case ODOTMETH:
+ if Debug.m != 0 {
+ Warnl(call.Pos, "devirtualizing %v to %v", call.Left, typ)
+ }
+ call.Op = OCALLMETH
+ call.Left = x
+ case ODOTINTER:
+ // Promoted method from embedded interface-typed field (#42279).
+ if Debug.m != 0 {
+ Warnl(call.Pos, "partially devirtualizing %v to %v", call.Left, typ)
+ }
+ call.Op = OCALLINTER
+ call.Left = x
+ default:
+ // TODO(mdempsky): Turn back into Fatalf after more testing.
+ if Debug.m != 0 {
+ Warnl(call.Pos, "failed to devirtualize %v (%v)", x, x.Op)
+ }
+ return
+ }
+
+ // Duplicated logic from typecheck for function call return
+ // value types.
+ //
+ // Receiver parameter size may have changed; need to update
+ // call.Type to get correct stack offsets for result
+ // parameters.
+ checkwidth(x.Type)
+ switch ft := x.Type; ft.NumResults() {
+ case 0:
+ case 1:
+ call.Type = ft.Results().Field(0).Type
+ default:
+ call.Type = ft.Results()
+ }
+}
diff --git a/src/cmd/compile/internal/gc/inl_test.go b/src/cmd/compile/internal/gc/inl_test.go
new file mode 100644
index 0000000..02735e5
--- /dev/null
+++ b/src/cmd/compile/internal/gc/inl_test.go
@@ -0,0 +1,269 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "bufio"
+ "internal/testenv"
+ "io"
+ "math/bits"
+ "os/exec"
+ "regexp"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+// TestIntendedInlining tests that specific runtime functions are inlined.
+// This allows refactoring for code clarity and re-use without fear that
+// changes to the compiler will cause silent performance regressions.
+func TestIntendedInlining(t *testing.T) {
+ if testing.Short() && testenv.Builder() == "" {
+ t.Skip("skipping in short mode")
+ }
+ testenv.MustHaveGoRun(t)
+ t.Parallel()
+
+ // want is the list of function names (by package) that should
+ // be inlinable. If they have no callers in their packages, they
+ // might not actually be inlined anywhere.
+ want := map[string][]string{
+ "runtime": {
+ "add",
+ "acquirem",
+ "add1",
+ "addb",
+ "adjustpanics",
+ "adjustpointer",
+ "alignDown",
+ "alignUp",
+ "bucketMask",
+ "bucketShift",
+ "chanbuf",
+ "deferArgs",
+ "deferclass",
+ "evacuated",
+ "fastlog2",
+ "fastrand",
+ "float64bits",
+ "funcPC",
+ "getArgInfoFast",
+ "getm",
+ "getMCache",
+ "isDirectIface",
+ "itabHashFunc",
+ "noescape",
+ "pcvalueCacheKey",
+ "readUnaligned32",
+ "readUnaligned64",
+ "releasem",
+ "roundupsize",
+ "stackmapdata",
+ "stringStructOf",
+ "subtract1",
+ "subtractb",
+ "tophash",
+ "totaldefersize",
+ "(*bmap).keys",
+ "(*bmap).overflow",
+ "(*waitq).enqueue",
+
+ // GC-related ones
+ "cgoInRange",
+ "gclinkptr.ptr",
+ "guintptr.ptr",
+ "heapBits.bits",
+ "heapBits.isPointer",
+ "heapBits.morePointers",
+ "heapBits.next",
+ "heapBitsForAddr",
+ "markBits.isMarked",
+ "muintptr.ptr",
+ "puintptr.ptr",
+ "spanOf",
+ "spanOfUnchecked",
+ "(*gcWork).putFast",
+ "(*gcWork).tryGetFast",
+ "(*guintptr).set",
+ "(*markBits).advance",
+ "(*mspan).allocBitsForIndex",
+ "(*mspan).base",
+ "(*mspan).markBitsForBase",
+ "(*mspan).markBitsForIndex",
+ "(*muintptr).set",
+ "(*puintptr).set",
+ },
+ "runtime/internal/sys": {},
+ "runtime/internal/math": {
+ "MulUintptr",
+ },
+ "bytes": {
+ "(*Buffer).Bytes",
+ "(*Buffer).Cap",
+ "(*Buffer).Len",
+ "(*Buffer).Grow",
+ "(*Buffer).Next",
+ "(*Buffer).Read",
+ "(*Buffer).ReadByte",
+ "(*Buffer).Reset",
+ "(*Buffer).String",
+ "(*Buffer).UnreadByte",
+ "(*Buffer).tryGrowByReslice",
+ },
+ "compress/flate": {
+ "byLiteral.Len",
+ "byLiteral.Less",
+ "byLiteral.Swap",
+ "(*dictDecoder).tryWriteCopy",
+ },
+ "encoding/base64": {
+ "assemble32",
+ "assemble64",
+ },
+ "unicode/utf8": {
+ "FullRune",
+ "FullRuneInString",
+ "RuneLen",
+ "ValidRune",
+ },
+ "reflect": {
+ "Value.CanAddr",
+ "Value.CanSet",
+ "Value.CanInterface",
+ "Value.IsValid",
+ "Value.pointer",
+ "add",
+ "align",
+ "flag.mustBe",
+ "flag.mustBeAssignable",
+ "flag.mustBeExported",
+ "flag.kind",
+ "flag.ro",
+ },
+ "regexp": {
+ "(*bitState).push",
+ },
+ "math/big": {
+ "bigEndianWord",
+ // The following functions require the math_big_pure_go build tag.
+ "addVW",
+ "subVW",
+ },
+ "math/rand": {
+ "(*rngSource).Int63",
+ "(*rngSource).Uint64",
+ },
+ }
+
+ if runtime.GOARCH != "386" && runtime.GOARCH != "mips64" && runtime.GOARCH != "mips64le" && runtime.GOARCH != "riscv64" {
+ // nextFreeFast calls sys.Ctz64, which on 386 is implemented in asm and is not inlinable.
+ // We currently don't have midstack inlining so nextFreeFast is also not inlinable on 386.
+ // On mips64x and riscv64, Ctz64 is not intrinsified and causes nextFreeFast too expensive
+ // to inline (Issue 22239).
+ want["runtime"] = append(want["runtime"], "nextFreeFast")
+ }
+ if runtime.GOARCH != "386" {
+ // As explained above, Ctz64 and Ctz32 are not Go code on 386.
+ // The same applies to Bswap32.
+ want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Ctz64")
+ want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Ctz32")
+ want["runtime/internal/sys"] = append(want["runtime/internal/sys"], "Bswap32")
+ }
+ if bits.UintSize == 64 {
+ // rotl_31 is only defined on 64-bit architectures
+ want["runtime"] = append(want["runtime"], "rotl_31")
+ }
+
+ switch runtime.GOARCH {
+ case "386", "wasm", "arm":
+ default:
+ // TODO(mvdan): As explained in /test/inline_sync.go, some
+ // architectures don't have atomic intrinsics, so these go over
+ // the inlining budget. Move back to the main table once that
+ // problem is solved.
+ want["sync"] = []string{
+ "(*Mutex).Lock",
+ "(*Mutex).Unlock",
+ "(*RWMutex).RLock",
+ "(*RWMutex).RUnlock",
+ "(*Once).Do",
+ }
+ }
+
+ // Functions that must actually be inlined; they must have actual callers.
+ must := map[string]bool{
+ "compress/flate.byLiteral.Len": true,
+ "compress/flate.byLiteral.Less": true,
+ "compress/flate.byLiteral.Swap": true,
+ }
+
+ notInlinedReason := make(map[string]string)
+ pkgs := make([]string, 0, len(want))
+ for pname, fnames := range want {
+ pkgs = append(pkgs, pname)
+ for _, fname := range fnames {
+ fullName := pname + "." + fname
+ if _, ok := notInlinedReason[fullName]; ok {
+ t.Errorf("duplicate func: %s", fullName)
+ }
+ notInlinedReason[fullName] = "unknown reason"
+ }
+ }
+
+ args := append([]string{"build", "-a", "-gcflags=all=-m -m", "-tags=math_big_pure_go"}, pkgs...)
+ cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), args...))
+ pr, pw := io.Pipe()
+ cmd.Stdout = pw
+ cmd.Stderr = pw
+ cmdErr := make(chan error, 1)
+ go func() {
+ cmdErr <- cmd.Run()
+ pw.Close()
+ }()
+ scanner := bufio.NewScanner(pr)
+ curPkg := ""
+ canInline := regexp.MustCompile(`: can inline ([^ ]*)`)
+ haveInlined := regexp.MustCompile(`: inlining call to ([^ ]*)`)
+ cannotInline := regexp.MustCompile(`: cannot inline ([^ ]*): (.*)`)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, "# ") {
+ curPkg = line[2:]
+ continue
+ }
+ if m := haveInlined.FindStringSubmatch(line); m != nil {
+ fname := m[1]
+ delete(notInlinedReason, curPkg+"."+fname)
+ continue
+ }
+ if m := canInline.FindStringSubmatch(line); m != nil {
+ fname := m[1]
+ fullname := curPkg + "." + fname
+ // If function must be inlined somewhere, being inlinable is not enough
+ if _, ok := must[fullname]; !ok {
+ delete(notInlinedReason, fullname)
+ continue
+ }
+ }
+ if m := cannotInline.FindStringSubmatch(line); m != nil {
+ fname, reason := m[1], m[2]
+ fullName := curPkg + "." + fname
+ if _, ok := notInlinedReason[fullName]; ok {
+ // cmd/compile gave us a reason why
+ notInlinedReason[fullName] = reason
+ }
+ continue
+ }
+ }
+ if err := <-cmdErr; err != nil {
+ t.Fatal(err)
+ }
+ if err := scanner.Err(); err != nil {
+ t.Fatal(err)
+ }
+ for fullName, reason := range notInlinedReason {
+ t.Errorf("%s was not inlined: %s", fullName, reason)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/lang_test.go b/src/cmd/compile/internal/gc/lang_test.go
new file mode 100644
index 0000000..72e7f07
--- /dev/null
+++ b/src/cmd/compile/internal/gc/lang_test.go
@@ -0,0 +1,64 @@
+// Copyright 2018 The Go Authors. 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 (
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+)
+
+const aliasSrc = `
+package x
+
+type T = int
+`
+
+func TestInvalidLang(t *testing.T) {
+ t.Parallel()
+
+ testenv.MustHaveGoBuild(t)
+
+ dir, err := ioutil.TempDir("", "TestInvalidLang")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ src := filepath.Join(dir, "alias.go")
+ if err := ioutil.WriteFile(src, []byte(aliasSrc), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ outfile := filepath.Join(dir, "alias.o")
+
+ if testLang(t, "go9.99", src, outfile) == nil {
+ t.Error("compilation with -lang=go9.99 succeeded unexpectedly")
+ }
+
+ // This test will have to be adjusted if we ever reach 1.99 or 2.0.
+ if testLang(t, "go1.99", src, outfile) == nil {
+ t.Error("compilation with -lang=go1.99 succeeded unexpectedly")
+ }
+
+ if testLang(t, "go1.8", src, outfile) == nil {
+ t.Error("compilation with -lang=go1.8 succeeded unexpectedly")
+ }
+
+ if err := testLang(t, "go1.9", src, outfile); err != nil {
+ t.Errorf("compilation with -lang=go1.9 failed unexpectedly: %v", err)
+ }
+}
+
+func testLang(t *testing.T, lang, src, outfile string) error {
+ run := []string{testenv.GoToolPath(t), "tool", "compile", "-lang", lang, "-o", outfile, src}
+ t.Log(run)
+ out, err := exec.Command(run[0], run[1:]...).CombinedOutput()
+ t.Logf("%s", out)
+ return err
+}
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
new file mode 100644
index 0000000..7cce371
--- /dev/null
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -0,0 +1,224 @@
+// Copyright 2009 The Go Authors. 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/syntax"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+ "fmt"
+ "strings"
+)
+
+// lineno is the source position at the start of the most recently lexed token.
+// TODO(gri) rename and eventually remove
+var lineno src.XPos
+
+func makePos(base *src.PosBase, line, col uint) src.XPos {
+ return Ctxt.PosTable.XPos(src.MakePos(base, line, col))
+}
+
+func isSpace(c rune) bool {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r'
+}
+
+func isQuoted(s string) bool {
+ return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
+}
+
+type PragmaFlag int16
+
+const (
+ // Func pragmas.
+ Nointerface PragmaFlag = 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
+ NoCheckPtr // func should not be instrumented by checkptr
+ 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 and cgo type pragmas
+ NotInHeap // values of this type must not be heap allocated
+
+ // Go command pragmas
+ GoBuildPragma
+)
+
+const (
+ FuncPragmas = Nointerface |
+ Noescape |
+ Norace |
+ Nosplit |
+ Noinline |
+ NoCheckPtr |
+ CgoUnsafeArgs |
+ UintptrEscapes |
+ Systemstack |
+ Nowritebarrier |
+ Nowritebarrierrec |
+ Yeswritebarrierrec
+
+ TypePragmas = NotInHeap
+)
+
+func pragmaFlag(verb string) PragmaFlag {
+ switch verb {
+ case "go:build":
+ return GoBuildPragma
+ case "go:nointerface":
+ if objabi.Fieldtrack_enabled != 0 {
+ return Nointerface
+ }
+ case "go:noescape":
+ return Noescape
+ case "go:norace":
+ return Norace
+ case "go:nosplit":
+ return Nosplit | NoCheckPtr // implies NoCheckPtr (see #34972)
+ case "go:noinline":
+ return Noinline
+ case "go:nocheckptr":
+ return NoCheckPtr
+ case "go:systemstack":
+ return Systemstack
+ case "go:nowritebarrier":
+ return Nowritebarrier
+ case "go:nowritebarrierrec":
+ return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
+ case "go:yeswritebarrierrec":
+ return Yeswritebarrierrec
+ case "go:cgo_unsafe_args":
+ return CgoUnsafeArgs | NoCheckPtr // implies NoCheckPtr (see #34968)
+ 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
+}
+
+// pragcgo is called concurrently if files are parsed concurrently.
+func (p *noder) pragcgo(pos syntax.Pos, text string) {
+ f := pragmaFields(text)
+
+ verb := strings.TrimPrefix(f[0], "go:")
+ f[0] = verb
+
+ switch verb {
+ case "cgo_export_static", "cgo_export_dynamic":
+ switch {
+ case len(f) == 2 && !isQuoted(f[1]):
+ case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
+ default:
+ p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf(`usage: //go:%s local [remote]`, verb)})
+ return
+ }
+ case "cgo_import_dynamic":
+ switch {
+ case len(f) == 2 && !isQuoted(f[1]):
+ case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
+ case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
+ f[3] = strings.Trim(f[3], `"`)
+ if objabi.GOOS == "aix" && f[3] != "" {
+ // On Aix, library pattern must be "lib.a/object.o"
+ // or "lib.a/libname.so.X"
+ n := strings.Split(f[3], "/")
+ if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || (!strings.HasSuffix(n[1], ".o") && !strings.Contains(n[1], ".so.")) {
+ p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`})
+ return
+ }
+ }
+ default:
+ p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`})
+ return
+ }
+ case "cgo_import_static":
+ switch {
+ case len(f) == 2 && !isQuoted(f[1]):
+ default:
+ p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_static local`})
+ return
+ }
+ case "cgo_dynamic_linker":
+ switch {
+ case len(f) == 2 && isQuoted(f[1]):
+ f[1] = strings.Trim(f[1], `"`)
+ default:
+ p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_dynamic_linker "path"`})
+ return
+ }
+ case "cgo_ldflag":
+ switch {
+ case len(f) == 2 && isQuoted(f[1]):
+ f[1] = strings.Trim(f[1], `"`)
+ default:
+ p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_ldflag "arg"`})
+ return
+ }
+ default:
+ return
+ }
+ p.pragcgobuf = append(p.pragcgobuf, f)
+}
+
+// pragmaFields is similar to strings.FieldsFunc(s, isSpace)
+// but does not split when inside double quoted regions and always
+// splits before the start and after the end of a double quoted region.
+// pragmaFields does not recognize escaped quotes. If a quote in s is not
+// closed the part after the opening quote will not be returned as a field.
+func pragmaFields(s string) []string {
+ var a []string
+ inQuote := false
+ fieldStart := -1 // Set to -1 when looking for start of field.
+ for i, c := range s {
+ switch {
+ case c == '"':
+ if inQuote {
+ inQuote = false
+ a = append(a, s[fieldStart:i+1])
+ fieldStart = -1
+ } else {
+ inQuote = true
+ if fieldStart >= 0 {
+ a = append(a, s[fieldStart:i])
+ }
+ fieldStart = i
+ }
+ case !inQuote && isSpace(c):
+ if fieldStart >= 0 {
+ a = append(a, s[fieldStart:i])
+ fieldStart = -1
+ }
+ default:
+ if fieldStart == -1 {
+ fieldStart = i
+ }
+ }
+ }
+ if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string.
+ a = append(a, s[fieldStart:])
+ }
+ return a
+}
diff --git a/src/cmd/compile/internal/gc/lex_test.go b/src/cmd/compile/internal/gc/lex_test.go
new file mode 100644
index 0000000..b2081a1
--- /dev/null
+++ b/src/cmd/compile/internal/gc/lex_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.
+
+package gc
+
+import (
+ "cmd/compile/internal/syntax"
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+func eq(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func TestPragmaFields(t *testing.T) {
+ var tests = []struct {
+ in string
+ want []string
+ }{
+ {"", []string{}},
+ {" \t ", []string{}},
+ {`""""`, []string{`""`, `""`}},
+ {" a'b'c ", []string{"a'b'c"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"\n☺\t☹\n", []string{"☺", "☹"}},
+ {`"1 2 " 3 " 4 5"`, []string{`"1 2 "`, `3`, `" 4 5"`}},
+ {`"1""2 3""4"`, []string{`"1"`, `"2 3"`, `"4"`}},
+ {`12"34"`, []string{`12`, `"34"`}},
+ {`12"34 `, []string{`12`}},
+ }
+
+ for _, tt := range tests {
+ got := pragmaFields(tt.in)
+ if !eq(got, tt.want) {
+ t.Errorf("pragmaFields(%q) = %v; want %v", tt.in, got, tt.want)
+ continue
+ }
+ }
+}
+
+func TestPragcgo(t *testing.T) {
+ type testStruct struct {
+ in string
+ want []string
+ }
+
+ var tests = []testStruct{
+ {`go:cgo_export_dynamic local`, []string{`cgo_export_dynamic`, `local`}},
+ {`go:cgo_export_dynamic local remote`, []string{`cgo_export_dynamic`, `local`, `remote`}},
+ {`go:cgo_export_dynamic local' remote'`, []string{`cgo_export_dynamic`, `local'`, `remote'`}},
+ {`go:cgo_export_static local`, []string{`cgo_export_static`, `local`}},
+ {`go:cgo_export_static local remote`, []string{`cgo_export_static`, `local`, `remote`}},
+ {`go:cgo_export_static local' remote'`, []string{`cgo_export_static`, `local'`, `remote'`}},
+ {`go:cgo_import_dynamic local`, []string{`cgo_import_dynamic`, `local`}},
+ {`go:cgo_import_dynamic local remote`, []string{`cgo_import_dynamic`, `local`, `remote`}},
+ {`go:cgo_import_static local`, []string{`cgo_import_static`, `local`}},
+ {`go:cgo_import_static local'`, []string{`cgo_import_static`, `local'`}},
+ {`go:cgo_dynamic_linker "/path/"`, []string{`cgo_dynamic_linker`, `/path/`}},
+ {`go:cgo_dynamic_linker "/p ath/"`, []string{`cgo_dynamic_linker`, `/p ath/`}},
+ {`go:cgo_ldflag "arg"`, []string{`cgo_ldflag`, `arg`}},
+ {`go:cgo_ldflag "a rg"`, []string{`cgo_ldflag`, `a rg`}},
+ }
+
+ if runtime.GOOS != "aix" {
+ tests = append(tests, []testStruct{
+ {`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}},
+ {`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}},
+ }...)
+ } else {
+ // cgo_import_dynamic with a library is slightly different on AIX
+ // as the library field must follow the pattern [libc.a/object.o].
+ tests = append(tests, []testStruct{
+ {`go:cgo_import_dynamic local remote "lib.a/obj.o"`, []string{`cgo_import_dynamic`, `local`, `remote`, `lib.a/obj.o`}},
+ // This test must fail.
+ {`go:cgo_import_dynamic local' remote' "library"`, []string{`<unknown position>: usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}},
+ }...)
+
+ }
+
+ var p noder
+ var nopos syntax.Pos
+ for _, tt := range tests {
+
+ p.err = make(chan syntax.Error)
+ gotch := make(chan [][]string, 1)
+ go func() {
+ p.pragcgobuf = nil
+ p.pragcgo(nopos, tt.in)
+ if p.pragcgobuf != nil {
+ gotch <- p.pragcgobuf
+ }
+ }()
+
+ select {
+ case e := <-p.err:
+ want := tt.want[0]
+ if e.Error() != want {
+ t.Errorf("pragcgo(%q) = %q; want %q", tt.in, e, want)
+ continue
+ }
+ case got := <-gotch:
+ want := [][]string{tt.want}
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want)
+ continue
+ }
+ }
+
+ }
+}
diff --git a/src/cmd/compile/internal/gc/logic_test.go b/src/cmd/compile/internal/gc/logic_test.go
new file mode 100644
index 0000000..78d2dd2
--- /dev/null
+++ b/src/cmd/compile/internal/gc/logic_test.go
@@ -0,0 +1,289 @@
+package gc
+
+import "testing"
+
+// Tests to make sure logic simplification rules are correct.
+
+func TestLogic64(t *testing.T) {
+ // test values to determine function equality
+ values := [...]int64{-1 << 63, 1<<63 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
+
+ // golden functions we use repeatedly
+ zero := func(x int64) int64 { return 0 }
+ id := func(x int64) int64 { return x }
+ or := func(x, y int64) int64 { return x | y }
+ and := func(x, y int64) int64 { return x & y }
+ y := func(x, y int64) int64 { return y }
+
+ for _, test := range [...]struct {
+ name string
+ f func(int64) int64
+ golden func(int64) int64
+ }{
+ {"x|x", func(x int64) int64 { return x | x }, id},
+ {"x|0", func(x int64) int64 { return x | 0 }, id},
+ {"x|-1", func(x int64) int64 { return x | -1 }, func(x int64) int64 { return -1 }},
+ {"x&x", func(x int64) int64 { return x & x }, id},
+ {"x&0", func(x int64) int64 { return x & 0 }, zero},
+ {"x&-1", func(x int64) int64 { return x & -1 }, id},
+ {"x^x", func(x int64) int64 { return x ^ x }, zero},
+ {"x^0", func(x int64) int64 { return x ^ 0 }, id},
+ {"x^-1", func(x int64) int64 { return x ^ -1 }, func(x int64) int64 { return ^x }},
+ {"x+0", func(x int64) int64 { return x + 0 }, id},
+ {"x-x", func(x int64) int64 { return x - x }, zero},
+ {"x*0", func(x int64) int64 { return x * 0 }, zero},
+ {"^^x", func(x int64) int64 { return ^^x }, id},
+ } {
+ for _, v := range values {
+ got := test.f(v)
+ want := test.golden(v)
+ if want != got {
+ t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
+ }
+ }
+ }
+ for _, test := range [...]struct {
+ name string
+ f func(int64, int64) int64
+ golden func(int64, int64) int64
+ }{
+ {"x|(x|y)", func(x, y int64) int64 { return x | (x | y) }, or},
+ {"x|(y|x)", func(x, y int64) int64 { return x | (y | x) }, or},
+ {"(x|y)|x", func(x, y int64) int64 { return (x | y) | x }, or},
+ {"(y|x)|x", func(x, y int64) int64 { return (y | x) | x }, or},
+ {"x&(x&y)", func(x, y int64) int64 { return x & (x & y) }, and},
+ {"x&(y&x)", func(x, y int64) int64 { return x & (y & x) }, and},
+ {"(x&y)&x", func(x, y int64) int64 { return (x & y) & x }, and},
+ {"(y&x)&x", func(x, y int64) int64 { return (y & x) & x }, and},
+ {"x^(x^y)", func(x, y int64) int64 { return x ^ (x ^ y) }, y},
+ {"x^(y^x)", func(x, y int64) int64 { return x ^ (y ^ x) }, y},
+ {"(x^y)^x", func(x, y int64) int64 { return (x ^ y) ^ x }, y},
+ {"(y^x)^x", func(x, y int64) int64 { return (y ^ x) ^ x }, y},
+ {"-(y-x)", func(x, y int64) int64 { return -(y - x) }, func(x, y int64) int64 { return x - y }},
+ {"(x+y)-x", func(x, y int64) int64 { return (x + y) - x }, y},
+ {"(y+x)-x", func(x, y int64) int64 { return (y + x) - x }, y},
+ } {
+ for _, v := range values {
+ for _, w := range values {
+ got := test.f(v, w)
+ want := test.golden(v, w)
+ if want != got {
+ t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
+ }
+ }
+ }
+ }
+}
+
+func TestLogic32(t *testing.T) {
+ // test values to determine function equality
+ values := [...]int32{-1 << 31, 1<<31 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
+
+ // golden functions we use repeatedly
+ zero := func(x int32) int32 { return 0 }
+ id := func(x int32) int32 { return x }
+ or := func(x, y int32) int32 { return x | y }
+ and := func(x, y int32) int32 { return x & y }
+ y := func(x, y int32) int32 { return y }
+
+ for _, test := range [...]struct {
+ name string
+ f func(int32) int32
+ golden func(int32) int32
+ }{
+ {"x|x", func(x int32) int32 { return x | x }, id},
+ {"x|0", func(x int32) int32 { return x | 0 }, id},
+ {"x|-1", func(x int32) int32 { return x | -1 }, func(x int32) int32 { return -1 }},
+ {"x&x", func(x int32) int32 { return x & x }, id},
+ {"x&0", func(x int32) int32 { return x & 0 }, zero},
+ {"x&-1", func(x int32) int32 { return x & -1 }, id},
+ {"x^x", func(x int32) int32 { return x ^ x }, zero},
+ {"x^0", func(x int32) int32 { return x ^ 0 }, id},
+ {"x^-1", func(x int32) int32 { return x ^ -1 }, func(x int32) int32 { return ^x }},
+ {"x+0", func(x int32) int32 { return x + 0 }, id},
+ {"x-x", func(x int32) int32 { return x - x }, zero},
+ {"x*0", func(x int32) int32 { return x * 0 }, zero},
+ {"^^x", func(x int32) int32 { return ^^x }, id},
+ } {
+ for _, v := range values {
+ got := test.f(v)
+ want := test.golden(v)
+ if want != got {
+ t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
+ }
+ }
+ }
+ for _, test := range [...]struct {
+ name string
+ f func(int32, int32) int32
+ golden func(int32, int32) int32
+ }{
+ {"x|(x|y)", func(x, y int32) int32 { return x | (x | y) }, or},
+ {"x|(y|x)", func(x, y int32) int32 { return x | (y | x) }, or},
+ {"(x|y)|x", func(x, y int32) int32 { return (x | y) | x }, or},
+ {"(y|x)|x", func(x, y int32) int32 { return (y | x) | x }, or},
+ {"x&(x&y)", func(x, y int32) int32 { return x & (x & y) }, and},
+ {"x&(y&x)", func(x, y int32) int32 { return x & (y & x) }, and},
+ {"(x&y)&x", func(x, y int32) int32 { return (x & y) & x }, and},
+ {"(y&x)&x", func(x, y int32) int32 { return (y & x) & x }, and},
+ {"x^(x^y)", func(x, y int32) int32 { return x ^ (x ^ y) }, y},
+ {"x^(y^x)", func(x, y int32) int32 { return x ^ (y ^ x) }, y},
+ {"(x^y)^x", func(x, y int32) int32 { return (x ^ y) ^ x }, y},
+ {"(y^x)^x", func(x, y int32) int32 { return (y ^ x) ^ x }, y},
+ {"-(y-x)", func(x, y int32) int32 { return -(y - x) }, func(x, y int32) int32 { return x - y }},
+ {"(x+y)-x", func(x, y int32) int32 { return (x + y) - x }, y},
+ {"(y+x)-x", func(x, y int32) int32 { return (y + x) - x }, y},
+ } {
+ for _, v := range values {
+ for _, w := range values {
+ got := test.f(v, w)
+ want := test.golden(v, w)
+ if want != got {
+ t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
+ }
+ }
+ }
+ }
+}
+
+func TestLogic16(t *testing.T) {
+ // test values to determine function equality
+ values := [...]int16{-1 << 15, 1<<15 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
+
+ // golden functions we use repeatedly
+ zero := func(x int16) int16 { return 0 }
+ id := func(x int16) int16 { return x }
+ or := func(x, y int16) int16 { return x | y }
+ and := func(x, y int16) int16 { return x & y }
+ y := func(x, y int16) int16 { return y }
+
+ for _, test := range [...]struct {
+ name string
+ f func(int16) int16
+ golden func(int16) int16
+ }{
+ {"x|x", func(x int16) int16 { return x | x }, id},
+ {"x|0", func(x int16) int16 { return x | 0 }, id},
+ {"x|-1", func(x int16) int16 { return x | -1 }, func(x int16) int16 { return -1 }},
+ {"x&x", func(x int16) int16 { return x & x }, id},
+ {"x&0", func(x int16) int16 { return x & 0 }, zero},
+ {"x&-1", func(x int16) int16 { return x & -1 }, id},
+ {"x^x", func(x int16) int16 { return x ^ x }, zero},
+ {"x^0", func(x int16) int16 { return x ^ 0 }, id},
+ {"x^-1", func(x int16) int16 { return x ^ -1 }, func(x int16) int16 { return ^x }},
+ {"x+0", func(x int16) int16 { return x + 0 }, id},
+ {"x-x", func(x int16) int16 { return x - x }, zero},
+ {"x*0", func(x int16) int16 { return x * 0 }, zero},
+ {"^^x", func(x int16) int16 { return ^^x }, id},
+ } {
+ for _, v := range values {
+ got := test.f(v)
+ want := test.golden(v)
+ if want != got {
+ t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
+ }
+ }
+ }
+ for _, test := range [...]struct {
+ name string
+ f func(int16, int16) int16
+ golden func(int16, int16) int16
+ }{
+ {"x|(x|y)", func(x, y int16) int16 { return x | (x | y) }, or},
+ {"x|(y|x)", func(x, y int16) int16 { return x | (y | x) }, or},
+ {"(x|y)|x", func(x, y int16) int16 { return (x | y) | x }, or},
+ {"(y|x)|x", func(x, y int16) int16 { return (y | x) | x }, or},
+ {"x&(x&y)", func(x, y int16) int16 { return x & (x & y) }, and},
+ {"x&(y&x)", func(x, y int16) int16 { return x & (y & x) }, and},
+ {"(x&y)&x", func(x, y int16) int16 { return (x & y) & x }, and},
+ {"(y&x)&x", func(x, y int16) int16 { return (y & x) & x }, and},
+ {"x^(x^y)", func(x, y int16) int16 { return x ^ (x ^ y) }, y},
+ {"x^(y^x)", func(x, y int16) int16 { return x ^ (y ^ x) }, y},
+ {"(x^y)^x", func(x, y int16) int16 { return (x ^ y) ^ x }, y},
+ {"(y^x)^x", func(x, y int16) int16 { return (y ^ x) ^ x }, y},
+ {"-(y-x)", func(x, y int16) int16 { return -(y - x) }, func(x, y int16) int16 { return x - y }},
+ {"(x+y)-x", func(x, y int16) int16 { return (x + y) - x }, y},
+ {"(y+x)-x", func(x, y int16) int16 { return (y + x) - x }, y},
+ } {
+ for _, v := range values {
+ for _, w := range values {
+ got := test.f(v, w)
+ want := test.golden(v, w)
+ if want != got {
+ t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
+ }
+ }
+ }
+ }
+}
+
+func TestLogic8(t *testing.T) {
+ // test values to determine function equality
+ values := [...]int8{-1 << 7, 1<<7 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
+
+ // golden functions we use repeatedly
+ zero := func(x int8) int8 { return 0 }
+ id := func(x int8) int8 { return x }
+ or := func(x, y int8) int8 { return x | y }
+ and := func(x, y int8) int8 { return x & y }
+ y := func(x, y int8) int8 { return y }
+
+ for _, test := range [...]struct {
+ name string
+ f func(int8) int8
+ golden func(int8) int8
+ }{
+ {"x|x", func(x int8) int8 { return x | x }, id},
+ {"x|0", func(x int8) int8 { return x | 0 }, id},
+ {"x|-1", func(x int8) int8 { return x | -1 }, func(x int8) int8 { return -1 }},
+ {"x&x", func(x int8) int8 { return x & x }, id},
+ {"x&0", func(x int8) int8 { return x & 0 }, zero},
+ {"x&-1", func(x int8) int8 { return x & -1 }, id},
+ {"x^x", func(x int8) int8 { return x ^ x }, zero},
+ {"x^0", func(x int8) int8 { return x ^ 0 }, id},
+ {"x^-1", func(x int8) int8 { return x ^ -1 }, func(x int8) int8 { return ^x }},
+ {"x+0", func(x int8) int8 { return x + 0 }, id},
+ {"x-x", func(x int8) int8 { return x - x }, zero},
+ {"x*0", func(x int8) int8 { return x * 0 }, zero},
+ {"^^x", func(x int8) int8 { return ^^x }, id},
+ } {
+ for _, v := range values {
+ got := test.f(v)
+ want := test.golden(v)
+ if want != got {
+ t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
+ }
+ }
+ }
+ for _, test := range [...]struct {
+ name string
+ f func(int8, int8) int8
+ golden func(int8, int8) int8
+ }{
+ {"x|(x|y)", func(x, y int8) int8 { return x | (x | y) }, or},
+ {"x|(y|x)", func(x, y int8) int8 { return x | (y | x) }, or},
+ {"(x|y)|x", func(x, y int8) int8 { return (x | y) | x }, or},
+ {"(y|x)|x", func(x, y int8) int8 { return (y | x) | x }, or},
+ {"x&(x&y)", func(x, y int8) int8 { return x & (x & y) }, and},
+ {"x&(y&x)", func(x, y int8) int8 { return x & (y & x) }, and},
+ {"(x&y)&x", func(x, y int8) int8 { return (x & y) & x }, and},
+ {"(y&x)&x", func(x, y int8) int8 { return (y & x) & x }, and},
+ {"x^(x^y)", func(x, y int8) int8 { return x ^ (x ^ y) }, y},
+ {"x^(y^x)", func(x, y int8) int8 { return x ^ (y ^ x) }, y},
+ {"(x^y)^x", func(x, y int8) int8 { return (x ^ y) ^ x }, y},
+ {"(y^x)^x", func(x, y int8) int8 { return (y ^ x) ^ x }, y},
+ {"-(y-x)", func(x, y int8) int8 { return -(y - x) }, func(x, y int8) int8 { return x - y }},
+ {"(x+y)-x", func(x, y int8) int8 { return (x + y) - x }, y},
+ {"(y+x)-x", func(x, y int8) int8 { return (y + x) - x }, y},
+ } {
+ for _, v := range values {
+ for _, w := range values {
+ got := test.f(v, w)
+ want := test.golden(v, w)
+ if want != got {
+ t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
+ }
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
new file mode 100644
index 0000000..a6963a3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/main.go
@@ -0,0 +1,1610 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run mkbuiltin.go
+
+package gc
+
+import (
+ "bufio"
+ "bytes"
+ "cmd/compile/internal/logopt"
+ "cmd/compile/internal/ssa"
+ "cmd/compile/internal/types"
+ "cmd/internal/bio"
+ "cmd/internal/dwarf"
+ "cmd/internal/goobj"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+ "cmd/internal/sys"
+ "flag"
+ "fmt"
+ "internal/goversion"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "regexp"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+var (
+ buildid string
+ spectre string
+ spectreIndex bool
+)
+
+var (
+ Debug_append int
+ Debug_checkptr int
+ Debug_closure int
+ Debug_compilelater int
+ debug_dclstack int
+ Debug_dumpptrs int
+ Debug_libfuzzer int
+ Debug_panic int
+ Debug_slice int
+ Debug_vlog bool
+ Debug_wb int
+ Debug_pctab string
+ Debug_locationlist int
+ Debug_typecheckinl int
+ Debug_gendwarfinl int
+ Debug_softfloat int
+ Debug_defer int
+)
+
+// Debug arguments.
+// These can be specified with the -d flag, as in "-d nil"
+// to set the debug_checknil variable.
+// Multiple options can be comma-separated.
+// Each option accepts an optional argument, as in "gcprog=2"
+var debugtab = []struct {
+ name string
+ help string
+ val interface{} // must be *int or *string
+}{
+ {"append", "print information about append compilation", &Debug_append},
+ {"checkptr", "instrument unsafe pointer conversions", &Debug_checkptr},
+ {"closure", "print information about closure compilation", &Debug_closure},
+ {"compilelater", "compile functions as late as possible", &Debug_compilelater},
+ {"disablenil", "disable nil checks", &disable_checknil},
+ {"dclstack", "run internal dclstack check", &debug_dclstack},
+ {"dumpptrs", "show Node pointer values in Dump/dumplist output", &Debug_dumpptrs},
+ {"gcprog", "print dump of GC programs", &Debug_gcprog},
+ {"libfuzzer", "coverage instrumentation for libfuzzer", &Debug_libfuzzer},
+ {"nil", "print information about nil checks", &Debug_checknil},
+ {"panic", "do not hide any compiler panic", &Debug_panic},
+ {"slice", "print information about slice compilation", &Debug_slice},
+ {"typeassert", "print information about type assertion inlining", &Debug_typeassert},
+ {"wb", "print information about write barriers", &Debug_wb},
+ {"export", "print export data", &Debug_export},
+ {"pctab", "print named pc-value table", &Debug_pctab},
+ {"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
+ {"typecheckinl", "eager typechecking of inline function bodies", &Debug_typecheckinl},
+ {"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl},
+ {"softfloat", "force compiler to emit soft-float code", &Debug_softfloat},
+ {"defer", "print information about defer compilation", &Debug_defer},
+ {"fieldtrack", "enable fieldtracking", &objabi.Fieldtrack_enabled},
+}
+
+const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
+
+<key> is one of:
+
+`
+
+const debugHelpFooter = `
+<value> is key-specific.
+
+Key "checkptr" supports values:
+ "0": instrumentation disabled
+ "1": conversions involving unsafe.Pointer are instrumented
+ "2": conversions to unsafe.Pointer force heap allocation
+
+Key "pctab" supports values:
+ "pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
+`
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n")
+ objabi.Flagprint(os.Stderr)
+ Exit(2)
+}
+
+func hidePanic() {
+ if Debug_panic == 0 && nsavederrors+nerrors > 0 {
+ // If we've already complained about things
+ // in the program, don't bother complaining
+ // about a panic too; let the user clean up
+ // the code and try again.
+ if err := recover(); err != nil {
+ errorexit()
+ }
+ }
+}
+
+// supportsDynlink reports whether or not the code generator for the given
+// architecture supports the -shared and -dynlink flags.
+func supportsDynlink(arch *sys.Arch) bool {
+ return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X)
+}
+
+// timing data for compiler phases
+var timings Timings
+var benchfile string
+
+var nowritebarrierrecCheck *nowritebarrierrecChecker
+
+// 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(archInit func(*Arch)) {
+ timings.Start("fe", "init")
+
+ defer hidePanic()
+
+ archInit(&thearch)
+
+ Ctxt = obj.Linknew(thearch.LinkArch)
+ Ctxt.DiagFunc = yyerror
+ Ctxt.DiagFlush = flusherrors
+ Ctxt.Bso = bufio.NewWriter(os.Stdout)
+
+ // UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
+ // on Darwin don't support it properly, especially since macOS 10.14 (Mojave). This is exposed as a flag
+ // to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
+ // See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
+ Ctxt.UseBASEntries = Ctxt.Headtype != objabi.Hdarwin
+
+ localpkg = types.NewPkg("", "")
+ localpkg.Prefix = "\"\""
+
+ // We won't know localpkg's height until after import
+ // processing. In the mean time, set to MaxPkgHeight to ensure
+ // height comparisons at least work until then.
+ localpkg.Height = types.MaxPkgHeight
+
+ // pseudo-package, for scoping
+ builtinpkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
+ builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
+
+ // pseudo-package, accessed by import "unsafe"
+ unsafepkg = types.NewPkg("unsafe", "unsafe")
+
+ // Pseudo-package that contains the compiler's builtin
+ // declarations for package runtime. These are declared in a
+ // separate package to avoid conflicts with package runtime's
+ // actual declarations, which may differ intentionally but
+ // insignificantly.
+ Runtimepkg = types.NewPkg("go.runtime", "runtime")
+ Runtimepkg.Prefix = "runtime"
+
+ // pseudo-packages used in symbol tables
+ itabpkg = types.NewPkg("go.itab", "go.itab")
+ itabpkg.Prefix = "go.itab" // not go%2eitab
+
+ itablinkpkg = types.NewPkg("go.itablink", "go.itablink")
+ itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
+
+ trackpkg = types.NewPkg("go.track", "go.track")
+ trackpkg.Prefix = "go.track" // not go%2etrack
+
+ // pseudo-package used for map zero values
+ mappkg = types.NewPkg("go.map", "go.map")
+ mappkg.Prefix = "go.map"
+
+ // pseudo-package used for methods with anonymous receivers
+ gopkg = types.NewPkg("go", "")
+
+ Wasm := objabi.GOARCH == "wasm"
+
+ // Whether the limit for stack-allocated objects is much smaller than normal.
+ // This can be helpful for diagnosing certain causes of GC latency. See #27732.
+ smallFrames := false
+ jsonLogOpt := ""
+
+ flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
+ flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
+ flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
+
+ objabi.Flagcount("%", "debug non-static initializers", &Debug.P)
+ objabi.Flagcount("B", "disable bounds checking", &Debug.B)
+ objabi.Flagcount("C", "disable printing of columns in error messages", &Debug.C)
+ objabi.Flagcount("E", "debug symbol export", &Debug.E)
+ objabi.Flagcount("K", "debug missing line numbers", &Debug.K)
+ objabi.Flagcount("L", "show full file names in error messages", &Debug.L)
+ objabi.Flagcount("N", "disable optimizations", &Debug.N)
+ objabi.Flagcount("S", "print assembly listing", &Debug.S)
+ objabi.Flagcount("W", "debug parse tree after type checking", &Debug.W)
+ objabi.Flagcount("e", "no limit on number of errors reported", &Debug.e)
+ objabi.Flagcount("h", "halt on error", &Debug.h)
+ objabi.Flagcount("j", "debug runtime-initialized variables", &Debug.j)
+ objabi.Flagcount("l", "disable inlining", &Debug.l)
+ objabi.Flagcount("m", "print optimization decisions", &Debug.m)
+ objabi.Flagcount("r", "debug generated wrappers", &Debug.r)
+ objabi.Flagcount("w", "debug type checking", &Debug.w)
+
+ objabi.Flagfn1("I", "add `directory` to import search path", addidir)
+ objabi.AddVersionFlag() // -V
+ flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
+ flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
+ flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
+ flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
+ flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
+ flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
+ flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
+ flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
+ objabi.Flagfn1("embedcfg", "read go:embed configuration from `file`", readEmbedCfg)
+ objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
+ objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
+ flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
+ flag.StringVar(&flag_lang, "lang", "", "release to compile for")
+ flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
+ objabi.Flagcount("live", "debug liveness analysis", &debuglive)
+ if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
+ flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
+ }
+ flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
+ flag.StringVar(&outfile, "o", "", "write output to `file`")
+ flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
+ flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o")
+ if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
+ flag.BoolVar(&flag_race, "race", false, "enable race detector")
+ }
+ flag.StringVar(&spectre, "spectre", spectre, "enable spectre mitigations in `list` (all, index, ret)")
+ if enableTrace {
+ flag.BoolVar(&trace, "t", false, "trace type-checking")
+ }
+ flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
+ flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
+ flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
+ var flag_shared bool
+ var flag_dynlink bool
+ if supportsDynlink(thearch.LinkArch.Arch) {
+ flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
+ flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
+ flag.BoolVar(&Ctxt.Flag_linkshared, "linkshared", false, "generate code that will be linked against Go shared libraries")
+ }
+ flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
+ flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
+ flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
+ var goversion string
+ flag.StringVar(&goversion, "goversion", "", "required version of the runtime")
+ var symabisPath string
+ flag.StringVar(&symabisPath, "symabis", "", "read symbol ABIs from `file`")
+ flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
+ flag.StringVar(&blockprofile, "blockprofile", "", "write block profile to `file`")
+ flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`")
+ flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
+ flag.BoolVar(&smallFrames, "smallframes", false, "reduce the size limit for stack allocated objects")
+ flag.BoolVar(&Ctxt.UseBASEntries, "dwarfbasentries", Ctxt.UseBASEntries, "use base address selection entries in DWARF")
+ flag.StringVar(&jsonLogOpt, "json", "", "version,destination for JSON compiler/optimizer logging")
+
+ objabi.Flagparse(usage)
+
+ Ctxt.Pkgpath = myimportpath
+
+ for _, f := range strings.Split(spectre, ",") {
+ f = strings.TrimSpace(f)
+ switch f {
+ default:
+ log.Fatalf("unknown setting -spectre=%s", f)
+ case "":
+ // nothing
+ case "all":
+ spectreIndex = true
+ Ctxt.Retpoline = true
+ case "index":
+ spectreIndex = true
+ case "ret":
+ Ctxt.Retpoline = true
+ }
+ }
+
+ if spectreIndex {
+ switch objabi.GOARCH {
+ case "amd64":
+ // ok
+ default:
+ log.Fatalf("GOARCH=%s does not support -spectre=index", objabi.GOARCH)
+ }
+ }
+
+ // Record flags that affect the build result. (And don't
+ // record flags that don't, since that would cause spurious
+ // changes in the binary.)
+ recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
+
+ if smallFrames {
+ maxStackVarSize = 128 * 1024
+ maxImplicitStackVarSize = 16 * 1024
+ }
+
+ Ctxt.Flag_shared = flag_dynlink || flag_shared
+ Ctxt.Flag_dynlink = flag_dynlink
+ Ctxt.Flag_optimize = Debug.N == 0
+
+ Ctxt.Debugasm = Debug.S
+ Ctxt.Debugvlog = Debug_vlog
+ if flagDWARF {
+ Ctxt.DebugInfo = debuginfo
+ Ctxt.GenAbstractFunc = genAbstractFunc
+ Ctxt.DwFixups = obj.NewDwarfFixupTable(Ctxt)
+ } else {
+ // turn off inline generation if no dwarf at all
+ genDwarfInline = 0
+ Ctxt.Flag_locationlists = false
+ }
+
+ if flag.NArg() < 1 && debugstr != "help" && debugstr != "ssa/help" {
+ usage()
+ }
+
+ if goversion != "" && goversion != runtime.Version() {
+ fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), goversion)
+ Exit(2)
+ }
+
+ checkLang()
+
+ if symabisPath != "" {
+ readSymABIs(symabisPath, myimportpath)
+ }
+
+ thearch.LinkArch.Init(Ctxt)
+
+ if outfile == "" {
+ p := flag.Arg(0)
+ if i := strings.LastIndex(p, "/"); i >= 0 {
+ p = p[i+1:]
+ }
+ if runtime.GOOS == "windows" {
+ if i := strings.LastIndex(p, `\`); i >= 0 {
+ p = p[i+1:]
+ }
+ }
+ if i := strings.LastIndex(p, "."); i >= 0 {
+ p = p[:i]
+ }
+ suffix := ".o"
+ if writearchive {
+ suffix = ".a"
+ }
+ outfile = p + suffix
+ }
+
+ startProfile()
+
+ if flag_race && flag_msan {
+ log.Fatal("cannot use both -race and -msan")
+ }
+ if flag_race || flag_msan {
+ // -race and -msan imply -d=checkptr for now.
+ Debug_checkptr = 1
+ }
+ if ispkgin(omit_pkgs) {
+ flag_race = false
+ flag_msan = false
+ }
+ if flag_race {
+ racepkg = types.NewPkg("runtime/race", "")
+ }
+ if flag_msan {
+ msanpkg = types.NewPkg("runtime/msan", "")
+ }
+ if flag_race || flag_msan {
+ instrumenting = true
+ }
+
+ if compiling_runtime && Debug.N != 0 {
+ log.Fatal("cannot disable optimizations while compiling runtime")
+ }
+ if nBackendWorkers < 1 {
+ log.Fatalf("-c must be at least 1, got %d", nBackendWorkers)
+ }
+ if nBackendWorkers > 1 && !concurrentBackendAllowed() {
+ log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
+ }
+ if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
+ log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
+ }
+
+ // parse -d argument
+ if debugstr != "" {
+ Split:
+ for _, name := range strings.Split(debugstr, ",") {
+ if name == "" {
+ continue
+ }
+ // display help about the -d option itself and quit
+ if name == "help" {
+ fmt.Print(debugHelpHeader)
+ maxLen := len("ssa/help")
+ for _, t := range debugtab {
+ if len(t.name) > maxLen {
+ maxLen = len(t.name)
+ }
+ }
+ for _, t := range debugtab {
+ fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
+ }
+ // ssa options have their own help
+ fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
+ fmt.Print(debugHelpFooter)
+ os.Exit(0)
+ }
+ val, valstring, haveInt := 1, "", true
+ if i := strings.IndexAny(name, "=:"); i >= 0 {
+ var err error
+ name, valstring = name[:i], name[i+1:]
+ val, err = strconv.Atoi(valstring)
+ if err != nil {
+ val, haveInt = 1, false
+ }
+ }
+ for _, t := range debugtab {
+ if t.name != name {
+ continue
+ }
+ switch vp := t.val.(type) {
+ case nil:
+ // Ignore
+ case *string:
+ *vp = valstring
+ case *int:
+ if !haveInt {
+ log.Fatalf("invalid debug value %v", name)
+ }
+ *vp = val
+ default:
+ panic("bad debugtab type")
+ }
+ continue Split
+ }
+ // special case for ssa for now
+ if strings.HasPrefix(name, "ssa/") {
+ // expect form ssa/phase/flag
+ // e.g. -d=ssa/generic_cse/time
+ // _ in phase name also matches space
+ phase := name[4:]
+ flag := "debug" // default flag is debug
+ if i := strings.Index(phase, "/"); i >= 0 {
+ flag = phase[i+1:]
+ phase = phase[:i]
+ }
+ err := ssa.PhaseOption(phase, flag, val, valstring)
+ if err != "" {
+ log.Fatalf(err)
+ }
+ continue Split
+ }
+ log.Fatalf("unknown debug key -d %s\n", name)
+ }
+ }
+
+ if compiling_runtime {
+ // Runtime can't use -d=checkptr, at least not yet.
+ Debug_checkptr = 0
+
+ // Fuzzing the runtime isn't interesting either.
+ Debug_libfuzzer = 0
+ }
+
+ // set via a -d flag
+ Ctxt.Debugpcln = Debug_pctab
+ if flagDWARF {
+ dwarf.EnableLogging(Debug_gendwarfinl != 0)
+ }
+
+ if Debug_softfloat != 0 {
+ thearch.SoftFloat = true
+ }
+
+ // enable inlining. for now:
+ // default: inlining on. (Debug.l == 1)
+ // -l: inlining off (Debug.l == 0)
+ // -l=2, -l=3: inlining on again, with extra debugging (Debug.l > 1)
+ if Debug.l <= 1 {
+ Debug.l = 1 - Debug.l
+ }
+
+ if jsonLogOpt != "" { // parse version,destination from json logging optimization.
+ logopt.LogJsonOption(jsonLogOpt)
+ }
+
+ ssaDump = os.Getenv("GOSSAFUNC")
+ ssaDir = os.Getenv("GOSSADIR")
+ if ssaDump != "" {
+ if strings.HasSuffix(ssaDump, "+") {
+ ssaDump = ssaDump[:len(ssaDump)-1]
+ ssaDumpStdout = true
+ }
+ spl := strings.Split(ssaDump, ":")
+ if len(spl) > 1 {
+ ssaDump = spl[0]
+ ssaDumpCFG = spl[1]
+ }
+ }
+
+ trackScopes = flagDWARF
+
+ Widthptr = thearch.LinkArch.PtrSize
+ Widthreg = thearch.LinkArch.RegSize
+
+ // initialize types package
+ // (we need to do this to break dependencies that otherwise
+ // would lead to import cycles)
+ types.Widthptr = Widthptr
+ types.Dowidth = dowidth
+ types.Fatalf = Fatalf
+ types.Sconv = func(s *types.Sym, flag, mode int) string {
+ return sconv(s, FmtFlag(flag), fmtMode(mode))
+ }
+ types.Tconv = func(t *types.Type, flag, mode int) string {
+ return tconv(t, FmtFlag(flag), fmtMode(mode))
+ }
+ types.FormatSym = func(sym *types.Sym, s fmt.State, verb rune, mode int) {
+ symFormat(sym, s, verb, fmtMode(mode))
+ }
+ types.FormatType = func(t *types.Type, s fmt.State, verb rune, mode int) {
+ typeFormat(t, s, verb, fmtMode(mode))
+ }
+ types.TypeLinkSym = func(t *types.Type) *obj.LSym {
+ return typenamesym(t).Linksym()
+ }
+ types.FmtLeft = int(FmtLeft)
+ types.FmtUnsigned = int(FmtUnsigned)
+ types.FErr = int(FErr)
+ types.Ctxt = Ctxt
+
+ initUniverse()
+
+ dclcontext = PEXTERN
+ nerrors = 0
+
+ autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
+
+ timings.Start("fe", "loadsys")
+ loadsys()
+
+ timings.Start("fe", "parse")
+ lines := parseFiles(flag.Args())
+ timings.Stop()
+ timings.AddEvent(int64(lines), "lines")
+
+ finishUniverse()
+
+ recordPackageName()
+
+ typecheckok = true
+
+ // Process top-level declarations in phases.
+
+ // Phase 1: const, type, and names and types of funcs.
+ // This will gather all the information about types
+ // and methods but doesn't depend on any of it.
+ //
+ // We also defer type alias declarations until phase 2
+ // to avoid cycles like #18640.
+ // TODO(gri) Remove this again once we have a fix for #25838.
+
+ // Don't use range--typecheck can add closures to xtop.
+ timings.Start("fe", "typecheck", "top1")
+ for i := 0; i < len(xtop); i++ {
+ n := xtop[i]
+ if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias()) {
+ xtop[i] = typecheck(n, ctxStmt)
+ }
+ }
+
+ // Phase 2: Variable assignments.
+ // 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++ {
+ n := xtop[i]
+ if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias() {
+ xtop[i] = typecheck(n, ctxStmt)
+ }
+ }
+
+ // 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++ {
+ n := xtop[i]
+ if n.Op == ODCLFUNC {
+ Curfn = n
+ decldepth = 1
+ saveerrors()
+ typecheckslice(Curfn.Nbody.Slice(), ctxStmt)
+ checkreturn(Curfn)
+ if nerrors != 0 {
+ Curfn.Nbody.Set(nil) // type errors; do not compile
+ }
+ // Now that we've checked whether n terminates,
+ // we can eliminate some obviously dead code.
+ deadcode(Curfn)
+ fcount++
+ }
+ }
+ // With all types checked, it's now safe to verify map keys. One single
+ // check past phase 9 isn't sufficient, as we may exit with other errors
+ // before then, thus skipping map key errors.
+ checkMapKeys()
+ timings.AddEvent(fcount, "funcs")
+
+ if nsavederrors+nerrors != 0 {
+ errorexit()
+ }
+
+ fninit(xtop)
+
+ // 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
+ capturevars(n)
+ }
+ }
+ capturevarscomplete = true
+
+ Curfn = nil
+
+ if nsavederrors+nerrors != 0 {
+ errorexit()
+ }
+
+ // Phase 5: Inlining
+ timings.Start("fe", "inlining")
+ if Debug_typecheckinl != 0 {
+ // Typecheck imported function bodies if Debug.l > 1,
+ // otherwise lazily when used or re-exported.
+ for _, n := range importlist {
+ if n.Func.Inl != nil {
+ saveerrors()
+ typecheckinl(n)
+ }
+ }
+
+ if nsavederrors+nerrors != 0 {
+ errorexit()
+ }
+ }
+
+ if Debug.l != 0 {
+ // Find functions that can be inlined and clone them before walk expands them.
+ visitBottomUp(xtop, func(list []*Node, recursive bool) {
+ numfns := numNonClosures(list)
+ for _, n := range list {
+ if !recursive || numfns > 1 {
+ // We allow inlining if there is no
+ // recursion, or the recursion cycle is
+ // across more than one function.
+ caninl(n)
+ } else {
+ if Debug.m > 1 {
+ fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
+ }
+ }
+ inlcalls(n)
+ }
+ })
+ }
+
+ for _, n := range xtop {
+ if n.Op == ODCLFUNC {
+ devirtualize(n)
+ }
+ }
+ Curfn = nil
+
+ // Phase 6: Escape analysis.
+ // Required for moving heap allocations onto stack,
+ // which in turn is required by the closure implementation,
+ // which stores the addresses of stack variables into the closure.
+ // If the closure does not escape, it needs to be on the stack
+ // or else the stack copier will not update it.
+ // Large values are also moved off stack in escape analysis;
+ // because large values may contain pointers, it must happen early.
+ timings.Start("fe", "escapes")
+ escapes(xtop)
+
+ // Collect information for go:nowritebarrierrec
+ // checking. This must happen before transformclosure.
+ // We'll do the final check after write barriers are
+ // inserted.
+ if compiling_runtime {
+ nowritebarrierrecCheck = newNowritebarrierrecChecker()
+ }
+
+ // Phase 7: Transform closure bodies to properly reference captured variables.
+ // This needs to happen before walk, because closures must be transformed
+ // before walk reaches a call of a closure.
+ timings.Start("fe", "xclosures")
+ for _, n := range xtop {
+ if n.Op == ODCLFUNC && n.Func.Closure != nil {
+ Curfn = n
+ transformclosure(n)
+ }
+ }
+
+ // Prepare for SSA compilation.
+ // This must be before peekitabs, because peekitabs
+ // can trigger function compilation.
+ initssaconfig()
+
+ // Just before compilation, compile itabs found on
+ // the right side of OCONVIFACE so that methods
+ // can be de-virtualized during compilation.
+ Curfn = nil
+ peekitabs()
+
+ // Phase 8: Compile top level functions.
+ // Don't use range--walk can add functions to xtop.
+ timings.Start("be", "compilefuncs")
+ fcount = 0
+ for i := 0; i < len(xtop); i++ {
+ n := xtop[i]
+ if n.Op == ODCLFUNC {
+ funccompile(n)
+ fcount++
+ }
+ }
+ timings.AddEvent(fcount, "funcs")
+
+ compileFunctions()
+
+ if nowritebarrierrecCheck != nil {
+ // Write barriers are now known. Check the
+ // call graph.
+ nowritebarrierrecCheck.check()
+ nowritebarrierrecCheck = nil
+ }
+
+ // Finalize DWARF inline routine DIEs, then explicitly turn off
+ // DWARF inlining gen so as to avoid problems with generated
+ // method wrappers.
+ if Ctxt.DwFixups != nil {
+ Ctxt.DwFixups.Finalize(myimportpath, Debug_gendwarfinl != 0)
+ Ctxt.DwFixups = nil
+ genDwarfInline = 0
+ }
+
+ // Phase 9: Check external declarations.
+ timings.Start("be", "externaldcls")
+ for i, n := range externdcl {
+ if n.Op == ONAME {
+ externdcl[i] = typecheck(externdcl[i], ctxExpr)
+ }
+ }
+ // Check the map keys again, since we typechecked the external
+ // declarations.
+ checkMapKeys()
+
+ if nerrors+nsavederrors != 0 {
+ errorexit()
+ }
+
+ // Write object data to disk.
+ timings.Start("be", "dumpobj")
+ dumpdata()
+ Ctxt.NumberSyms()
+ dumpobj()
+ if asmhdr != "" {
+ dumpasmhdr()
+ }
+
+ // Check whether any of the functions we have compiled have gigantic stack frames.
+ sort.Slice(largeStackFrames, func(i, j int) bool {
+ return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
+ })
+ for _, large := range largeStackFrames {
+ if large.callee != 0 {
+ yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
+ } else {
+ yyerrorl(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
+ }
+ }
+
+ if len(funcStack) != 0 {
+ Fatalf("funcStack is non-empty: %v", len(funcStack))
+ }
+ if len(compilequeue) != 0 {
+ Fatalf("%d uncompiled functions", len(compilequeue))
+ }
+
+ logopt.FlushLoggedOpts(Ctxt, myimportpath)
+
+ if nerrors+nsavederrors != 0 {
+ errorexit()
+ }
+
+ flusherrors()
+ timings.Stop()
+
+ if benchfile != "" {
+ if err := writebench(benchfile); err != nil {
+ log.Fatalf("cannot write benchmark data: %v", err)
+ }
+ }
+}
+
+// numNonClosures returns the number of functions in list which are not closures.
+func numNonClosures(list []*Node) int {
+ count := 0
+ for _, n := range list {
+ if n.Func.Closure == nil {
+ count++
+ }
+ }
+ return count
+}
+
+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:", objabi.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{}
+ packageFile map[string]string // nil means not in use
+)
+
+func addImportMap(s string) {
+ if strings.Count(s, "=") != 1 {
+ log.Fatal("-importmap argument must be of the form source=actual")
+ }
+ i := strings.Index(s, "=")
+ source, actual := s[:i], s[i+1:]
+ if source == "" || actual == "" {
+ log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
+ }
+ importMap[source] = actual
+}
+
+func readImportCfg(file string) {
+ packageFile = map[string]string{}
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ log.Fatalf("-importcfg: %v", err)
+ }
+
+ for lineNum, line := range strings.Split(string(data), "\n") {
+ lineNum++ // 1-based
+ line = strings.TrimSpace(line)
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+
+ var verb, args string
+ if i := strings.Index(line, " "); i < 0 {
+ verb = line
+ } else {
+ verb, args = line[:i], strings.TrimSpace(line[i+1:])
+ }
+ var before, after string
+ if i := strings.Index(args, "="); i >= 0 {
+ before, after = args[:i], args[i+1:]
+ }
+ switch verb {
+ default:
+ log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
+ case "importmap":
+ if before == "" || after == "" {
+ log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
+ }
+ importMap[before] = after
+ case "packagefile":
+ if before == "" || after == "" {
+ log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
+ }
+ packageFile[before] = after
+ }
+ }
+}
+
+// symabiDefs and symabiRefs record the defined and referenced ABIs of
+// symbols required by non-Go code. These are keyed by link symbol
+// name, where the local package prefix is always `"".`
+var symabiDefs, symabiRefs map[string]obj.ABI
+
+// readSymABIs reads a symabis file that specifies definitions and
+// references of text symbols by ABI.
+//
+// The symabis format is a set of lines, where each line is a sequence
+// of whitespace-separated fields. The first field is a verb and is
+// either "def" for defining a symbol ABI or "ref" for referencing a
+// symbol using an ABI. For both "def" and "ref", the second field is
+// the symbol name and the third field is the ABI name, as one of the
+// named cmd/internal/obj.ABI constants.
+func readSymABIs(file, myimportpath string) {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ log.Fatalf("-symabis: %v", err)
+ }
+
+ symabiDefs = make(map[string]obj.ABI)
+ symabiRefs = make(map[string]obj.ABI)
+
+ localPrefix := ""
+ if myimportpath != "" {
+ // Symbols in this package may be written either as
+ // "".X or with the package's import path already in
+ // the symbol.
+ localPrefix = objabi.PathToPrefix(myimportpath) + "."
+ }
+
+ for lineNum, line := range strings.Split(string(data), "\n") {
+ lineNum++ // 1-based
+ line = strings.TrimSpace(line)
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+
+ parts := strings.Fields(line)
+ switch parts[0] {
+ case "def", "ref":
+ // Parse line.
+ if len(parts) != 3 {
+ log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
+ }
+ sym, abistr := parts[1], parts[2]
+ abi, valid := obj.ParseABI(abistr)
+ if !valid {
+ log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
+ }
+
+ // If the symbol is already prefixed with
+ // myimportpath, rewrite it to start with ""
+ // so it matches the compiler's internal
+ // symbol names.
+ if localPrefix != "" && strings.HasPrefix(sym, localPrefix) {
+ sym = `"".` + sym[len(localPrefix):]
+ }
+
+ // Record for later.
+ if parts[0] == "def" {
+ symabiDefs[sym] = abi
+ } else {
+ symabiRefs[sym] = abi
+ }
+ default:
+ log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
+ }
+ }
+}
+
+func saveerrors() {
+ nsavederrors += nerrors
+ nerrors = 0
+}
+
+func arsize(b *bufio.Reader, name string) int {
+ var buf [ArhdrSize]byte
+ if _, err := io.ReadFull(b, buf[:]); err != nil {
+ return -1
+ }
+ aname := strings.Trim(string(buf[0:16]), " ")
+ if !strings.HasPrefix(aname, name) {
+ return -1
+ }
+ asize := strings.Trim(string(buf[48:58]), " ")
+ i, _ := strconv.Atoi(asize)
+ return i
+}
+
+var idirs []string
+
+func addidir(dir string) {
+ if dir != "" {
+ idirs = append(idirs, dir)
+ }
+}
+
+func isDriveLetter(b byte) bool {
+ return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
+}
+
+// is this path a local name? begins with ./ or ../ or /
+func islocalname(name string) bool {
+ return strings.HasPrefix(name, "/") ||
+ runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
+ strings.HasPrefix(name, "./") || name == "." ||
+ strings.HasPrefix(name, "../") || name == ".."
+}
+
+func findpkg(name string) (file string, ok bool) {
+ if islocalname(name) {
+ if nolocalimports {
+ return "", false
+ }
+
+ if packageFile != nil {
+ file, ok = packageFile[name]
+ return file, ok
+ }
+
+ // try .a before .6. important for building libraries:
+ // if there is an array.6 in the array.a library,
+ // want to find all of array.a, not just array.6.
+ file = fmt.Sprintf("%s.a", name)
+ if _, err := os.Stat(file); err == nil {
+ return file, true
+ }
+ file = fmt.Sprintf("%s.o", name)
+ if _, err := os.Stat(file); err == nil {
+ return file, true
+ }
+ return "", false
+ }
+
+ // local imports should be canonicalized already.
+ // don't want to see "encoding/../encoding/base64"
+ // as different from "encoding/base64".
+ if q := path.Clean(name); q != name {
+ yyerror("non-canonical import path %q (should be %q)", name, q)
+ return "", false
+ }
+
+ if packageFile != nil {
+ file, ok = packageFile[name]
+ return file, ok
+ }
+
+ for _, dir := range idirs {
+ file = fmt.Sprintf("%s/%s.a", dir, name)
+ if _, err := os.Stat(file); err == nil {
+ return file, true
+ }
+ file = fmt.Sprintf("%s/%s.o", dir, name)
+ if _, err := os.Stat(file); err == nil {
+ return file, true
+ }
+ }
+
+ if objabi.GOROOT != "" {
+ suffix := ""
+ suffixsep := ""
+ if flag_installsuffix != "" {
+ suffixsep = "_"
+ suffix = flag_installsuffix
+ } else if flag_race {
+ suffixsep = "_"
+ suffix = "race"
+ } else if flag_msan {
+ suffixsep = "_"
+ suffix = "msan"
+ }
+
+ file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
+ if _, err := os.Stat(file); err == nil {
+ return file, true
+ }
+ file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
+ if _, err := os.Stat(file); err == nil {
+ return file, true
+ }
+ }
+
+ return "", false
+}
+
+// loadsys loads the definitions for the low-level runtime functions,
+// so that the compiler can generate calls to them,
+// but does not make them visible to user code.
+func loadsys() {
+ types.Block = 1
+
+ inimport = true
+ typecheckok = true
+
+ typs := runtimeTypes()
+ for _, d := range &runtimeDecls {
+ sym := Runtimepkg.Lookup(d.name)
+ typ := typs[d.typ]
+ switch d.tag {
+ case funcTag:
+ importfunc(Runtimepkg, src.NoXPos, sym, typ)
+ case varTag:
+ importvar(Runtimepkg, src.NoXPos, sym, typ)
+ default:
+ Fatalf("unhandled declaration tag %v", d.tag)
+ }
+ }
+
+ typecheckok = false
+ inimport = false
+}
+
+// myheight tracks the local package's height based on packages
+// imported so far.
+var myheight int
+
+func importfile(f *Val) *types.Pkg {
+ path_, ok := f.U.(string)
+ if !ok {
+ yyerror("import path must be a string")
+ return nil
+ }
+
+ if len(path_) == 0 {
+ yyerror("import path is empty")
+ return nil
+ }
+
+ if isbadimport(path_, false) {
+ return nil
+ }
+
+ // The package name main is no longer reserved,
+ // but we reserve the import path "main" to identify
+ // the main package, just as we reserve the import
+ // path "math" to identify the standard math package.
+ if path_ == "main" {
+ yyerror("cannot import \"main\"")
+ errorexit()
+ }
+
+ if myimportpath != "" && path_ == myimportpath {
+ yyerror("import %q while compiling that package (import cycle)", path_)
+ errorexit()
+ }
+
+ if mapped, ok := importMap[path_]; ok {
+ path_ = mapped
+ }
+
+ if path_ == "unsafe" {
+ return unsafepkg
+ }
+
+ if islocalname(path_) {
+ if path_[0] == '/' {
+ yyerror("import path cannot be absolute path")
+ return nil
+ }
+
+ prefix := Ctxt.Pathname
+ if localimport != "" {
+ prefix = localimport
+ }
+ path_ = path.Join(prefix, path_)
+
+ if isbadimport(path_, true) {
+ return nil
+ }
+ }
+
+ file, found := findpkg(path_)
+ if !found {
+ yyerror("can't find import: %q", path_)
+ errorexit()
+ }
+
+ importpkg := types.NewPkg(path_, "")
+ if importpkg.Imported {
+ return importpkg
+ }
+
+ importpkg.Imported = true
+
+ imp, err := bio.Open(file)
+ if err != nil {
+ yyerror("can't open import: %q: %v", path_, err)
+ errorexit()
+ }
+ defer imp.Close()
+
+ // check object header
+ p, err := imp.ReadString('\n')
+ if err != nil {
+ yyerror("import %s: reading input: %v", file, err)
+ errorexit()
+ }
+
+ if p == "!<arch>\n" { // package archive
+ // package export block should be first
+ sz := arsize(imp.Reader, "__.PKGDEF")
+ if sz <= 0 {
+ yyerror("import %s: not a package file", file)
+ errorexit()
+ }
+ p, err = imp.ReadString('\n')
+ if err != nil {
+ yyerror("import %s: reading input: %v", file, err)
+ errorexit()
+ }
+ }
+
+ if !strings.HasPrefix(p, "go object ") {
+ yyerror("import %s: not a go object file: %s", file, p)
+ errorexit()
+ }
+ q := fmt.Sprintf("%s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
+ if p[10:] != q {
+ yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
+ errorexit()
+ }
+
+ // process header lines
+ for {
+ p, err = imp.ReadString('\n')
+ if err != nil {
+ yyerror("import %s: reading input: %v", file, err)
+ errorexit()
+ }
+ if p == "\n" {
+ break // header ends with blank line
+ }
+ }
+
+ // In the importfile, if we find:
+ // $$\n (textual format): not supported anymore
+ // $$B\n (binary format) : import directly, then feed the lexer a dummy statement
+
+ // look for $$
+ var c byte
+ for {
+ c, err = imp.ReadByte()
+ if err != nil {
+ break
+ }
+ if c == '$' {
+ c, err = imp.ReadByte()
+ if c == '$' || err != nil {
+ break
+ }
+ }
+ }
+
+ // get character after $$
+ if err == nil {
+ c, _ = imp.ReadByte()
+ }
+
+ var fingerprint goobj.FingerprintType
+ switch c {
+ case '\n':
+ yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
+ return nil
+
+ case 'B':
+ if Debug_export != 0 {
+ fmt.Printf("importing %s (%s)\n", path_, file)
+ }
+ imp.ReadByte() // skip \n after $$B
+
+ c, err = imp.ReadByte()
+ if err != nil {
+ yyerror("import %s: reading input: %v", file, err)
+ errorexit()
+ }
+
+ // Indexed format is distinguished by an 'i' byte,
+ // whereas previous export formats started with 'c', 'd', or 'v'.
+ if c != 'i' {
+ yyerror("import %s: unexpected package format byte: %v", file, c)
+ errorexit()
+ }
+ fingerprint = iimport(importpkg, imp)
+
+ default:
+ yyerror("no import in %q", path_)
+ errorexit()
+ }
+
+ // assume files move (get installed) so don't record the full path
+ if packageFile != nil {
+ // If using a packageFile map, assume path_ can be recorded directly.
+ Ctxt.AddImport(path_, fingerprint)
+ } else {
+ // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
+ Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint)
+ }
+
+ if importpkg.Height >= myheight {
+ myheight = importpkg.Height + 1
+ }
+
+ return importpkg
+}
+
+func pkgnotused(lineno src.XPos, path string, name string) {
+ // If the package was imported with a name other than the final
+ // import path element, show it explicitly in the error message.
+ // Note that this handles both renamed imports and imports of
+ // packages containing unconventional package declarations.
+ // Note that this uses / always, even on Windows, because Go import
+ // paths always use forward slashes.
+ elem := path
+ if i := strings.LastIndex(elem, "/"); i >= 0 {
+ elem = elem[i+1:]
+ }
+ if name == "" || elem == name {
+ yyerrorl(lineno, "imported and not used: %q", path)
+ } else {
+ yyerrorl(lineno, "imported and not used: %q as %s", path, name)
+ }
+}
+
+func mkpackage(pkgname string) {
+ if localpkg.Name == "" {
+ if pkgname == "_" {
+ yyerror("invalid package name _")
+ }
+ localpkg.Name = pkgname
+ } else {
+ if pkgname != localpkg.Name {
+ yyerror("package %s; expected %s", pkgname, localpkg.Name)
+ }
+ }
+}
+
+func clearImports() {
+ type importedPkg struct {
+ pos src.XPos
+ path string
+ name string
+ }
+ var unused []importedPkg
+
+ for _, s := range localpkg.Syms {
+ n := asNode(s.Def)
+ if n == nil {
+ continue
+ }
+ if n.Op == OPACK {
+ // throw away top-level package name left over
+ // from previous file.
+ // leave s->block set to cause redeclaration
+ // errors if a conflicting top-level name is
+ // introduced by a different file.
+ if !n.Name.Used() && nsyntaxerrors == 0 {
+ unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name})
+ }
+ s.Def = nil
+ continue
+ }
+ if IsAlias(s) {
+ // throw away top-level name left over
+ // from previous import . "x"
+ if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 {
+ unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""})
+ n.Name.Pack.Name.SetUsed(true)
+ }
+ s.Def = nil
+ continue
+ }
+ }
+
+ sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
+ for _, pkg := range unused {
+ pkgnotused(pkg.pos, pkg.path, pkg.name)
+ }
+}
+
+func IsAlias(sym *types.Sym) bool {
+ return sym.Def != nil && asNode(sym.Def).Sym != sym
+}
+
+// By default, assume any debug flags are incompatible with concurrent
+// compilation. A few are safe and potentially in common use for
+// normal compiles, though; return true for those.
+func concurrentFlagOk() bool {
+ // Report whether any debug flag that would prevent concurrent
+ // compilation is set, by zeroing out the allowed ones and then
+ // checking if the resulting struct is zero.
+ d := Debug
+ d.B = 0 // disable bounds checking
+ d.C = 0 // disable printing of columns in error messages
+ d.e = 0 // no limit on errors; errors all come from non-concurrent code
+ d.N = 0 // disable optimizations
+ d.l = 0 // disable inlining
+ d.w = 0 // all printing happens before compilation
+ d.W = 0 // all printing happens before compilation
+ d.S = 0 // printing disassembly happens at the end (but see concurrentBackendAllowed below)
+
+ return d == DebugFlags{}
+}
+
+func concurrentBackendAllowed() bool {
+ if !concurrentFlagOk() {
+ return false
+ }
+
+ // Debug.S by itself is ok, because all printing occurs
+ // while writing the object file, and that is non-concurrent.
+ // Adding Debug_vlog, however, causes Debug.S to also print
+ // while flushing the plist, which happens concurrently.
+ if Debug_vlog || debugstr != "" || debuglive > 0 {
+ return false
+ }
+ // TODO: Test and delete this condition.
+ if objabi.Fieldtrack_enabled != 0 {
+ return false
+ }
+ // TODO: fix races and enable the following flags
+ if Ctxt.Flag_shared || Ctxt.Flag_dynlink || flag_race {
+ return false
+ }
+ return true
+}
+
+// recordFlags records the specified command-line flags to be placed
+// in the DWARF info.
+func recordFlags(flags ...string) {
+ if myimportpath == "" {
+ // We can't record the flags if we don't know what the
+ // package name is.
+ return
+ }
+
+ type BoolFlag interface {
+ IsBoolFlag() bool
+ }
+ type CountFlag interface {
+ IsCountFlag() bool
+ }
+ var cmd bytes.Buffer
+ for _, name := range flags {
+ f := flag.Lookup(name)
+ if f == nil {
+ continue
+ }
+ getter := f.Value.(flag.Getter)
+ if getter.String() == f.DefValue {
+ // Flag has default value, so omit it.
+ continue
+ }
+ if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
+ val, ok := getter.Get().(bool)
+ if ok && val {
+ fmt.Fprintf(&cmd, " -%s", f.Name)
+ continue
+ }
+ }
+ if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
+ val, ok := getter.Get().(int)
+ if ok && val == 1 {
+ fmt.Fprintf(&cmd, " -%s", f.Name)
+ continue
+ }
+ }
+ fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
+ }
+
+ if cmd.Len() == 0 {
+ return
+ }
+ s := Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + myimportpath)
+ s.Type = objabi.SDWARFCUINFO
+ // Sometimes (for example when building tests) we can link
+ // together two package main archives. So allow dups.
+ s.Set(obj.AttrDuplicateOK, true)
+ Ctxt.Data = append(Ctxt.Data, s)
+ s.P = cmd.Bytes()[1:]
+}
+
+// recordPackageName records the name of the package being
+// compiled, so that the linker can save it in the compile unit's DIE.
+func recordPackageName() {
+ s := Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + myimportpath)
+ s.Type = objabi.SDWARFCUINFO
+ // Sometimes (for example when building tests) we can link
+ // together two package main archives. So allow dups.
+ s.Set(obj.AttrDuplicateOK, true)
+ Ctxt.Data = append(Ctxt.Data, s)
+ s.P = []byte(localpkg.Name)
+}
+
+// flag_lang is the language version we are compiling for, set by the -lang flag.
+var flag_lang string
+
+// currentLang returns the current language version.
+func currentLang() string {
+ return fmt.Sprintf("go1.%d", goversion.Version)
+}
+
+// goVersionRE is a regular expression that matches the valid
+// arguments to the -lang flag.
+var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
+
+// A lang is a language version broken into major and minor numbers.
+type lang struct {
+ major, minor int
+}
+
+// langWant is the desired language version set by the -lang flag.
+// If the -lang flag is not set, this is the zero value, meaning that
+// any language version is supported.
+var langWant lang
+
+// langSupported reports whether language version major.minor is
+// supported in a particular package.
+func langSupported(major, minor int, pkg *types.Pkg) bool {
+ if pkg == nil {
+ // TODO(mdempsky): Set Pkg for local types earlier.
+ pkg = localpkg
+ }
+ if pkg != localpkg {
+ // Assume imported packages passed type-checking.
+ return true
+ }
+
+ if langWant.major == 0 && langWant.minor == 0 {
+ return true
+ }
+ return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
+}
+
+// checkLang verifies that the -lang flag holds a valid value, and
+// exits if not. It initializes data used by langSupported.
+func checkLang() {
+ if flag_lang == "" {
+ return
+ }
+
+ var err error
+ langWant, err = parseLang(flag_lang)
+ if err != nil {
+ log.Fatalf("invalid value %q for -lang: %v", flag_lang, err)
+ }
+
+ if def := currentLang(); flag_lang != def {
+ defVers, err := parseLang(def)
+ if err != nil {
+ log.Fatalf("internal error parsing default lang %q: %v", def, err)
+ }
+ if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) {
+ log.Fatalf("invalid value %q for -lang: max known version is %q", flag_lang, def)
+ }
+ }
+}
+
+// parseLang parses a -lang option into a langVer.
+func parseLang(s string) (lang, error) {
+ matches := goVersionRE.FindStringSubmatch(s)
+ if matches == nil {
+ return lang{}, fmt.Errorf(`should be something like "go1.12"`)
+ }
+ major, err := strconv.Atoi(matches[1])
+ if err != nil {
+ return lang{}, err
+ }
+ minor, err := strconv.Atoi(matches[2])
+ if err != nil {
+ return lang{}, err
+ }
+ return lang{major: major, minor: minor}, nil
+}
diff --git a/src/cmd/compile/internal/gc/mapfile_mmap.go b/src/cmd/compile/internal/gc/mapfile_mmap.go
new file mode 100644
index 0000000..9483688
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mapfile_mmap.go
@@ -0,0 +1,48 @@
+// Copyright 2018 The Go Authors. 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 gc
+
+import (
+ "os"
+ "reflect"
+ "syscall"
+ "unsafe"
+)
+
+// TODO(mdempsky): Is there a higher-level abstraction that still
+// works well for iimport?
+
+// mapFile returns length bytes from the file starting at the
+// specified offset as a string.
+func mapFile(f *os.File, offset, length int64) (string, error) {
+ // POSIX mmap: "The implementation may require that off is a
+ // multiple of the page size."
+ x := offset & int64(os.Getpagesize()-1)
+ offset -= x
+ length += x
+
+ buf, err := syscall.Mmap(int(f.Fd()), offset, int(length), syscall.PROT_READ, syscall.MAP_SHARED)
+ keepAlive(f)
+ if err != nil {
+ return "", err
+ }
+
+ buf = buf[x:]
+ pSlice := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
+
+ var res string
+ pString := (*reflect.StringHeader)(unsafe.Pointer(&res))
+
+ pString.Data = pSlice.Data
+ pString.Len = pSlice.Len
+
+ return res, nil
+}
+
+// keepAlive is a reimplementation of runtime.KeepAlive, which wasn't
+// added until Go 1.7, whereas we need to compile with Go 1.4.
+var keepAlive = func(interface{}) {}
diff --git a/src/cmd/compile/internal/gc/mapfile_read.go b/src/cmd/compile/internal/gc/mapfile_read.go
new file mode 100644
index 0000000..c6f68ed
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mapfile_read.go
@@ -0,0 +1,21 @@
+// Copyright 2018 The Go Authors. 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 gc
+
+import (
+ "io"
+ "os"
+)
+
+func mapFile(f *os.File, offset, length int64) (string, error) {
+ buf := make([]byte, length)
+ _, err := io.ReadFull(io.NewSectionReader(f, offset, length), buf)
+ if err != nil {
+ return "", err
+ }
+ return string(buf), nil
+}
diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go
new file mode 100644
index 0000000..63d2a12
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mkbuiltin.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.
+
+// +build ignore
+
+// 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"
+ "path/filepath"
+ "strconv"
+ "strings"
+)
+
+var stdout = flag.Bool("stdout", false, "write to stdout instead of builtin.go")
+
+func main() {
+ flag.Parse()
+
+ var b bytes.Buffer
+ fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
+ fmt.Fprintln(&b)
+ fmt.Fprintln(&b, "package gc")
+ fmt.Fprintln(&b)
+ fmt.Fprintln(&b, `import "cmd/compile/internal/types"`)
+
+ mkbuiltin(&b, "runtime")
+
+ out, err := format.Source(b.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if *stdout {
+ _, err = os.Stdout.Write(out)
+ } else {
+ err = ioutil.WriteFile("builtin.go", out, 0666)
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func mkbuiltin(w io.Writer, name string) {
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, filepath.Join("builtin", name+".go"), nil, 0)
+ if 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.IMPORT {
+ if len(decl.Specs) != 1 || decl.Specs[0].(*ast.ImportSpec).Path.Value != "\"unsafe\"" {
+ log.Fatal("runtime cannot import other package")
+ }
+ continue
+ }
+ if decl.Tok != token.VAR {
+ log.Fatal("unhandled declaration kind", decl.Tok)
+ }
+ 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)
+ }
+ }
+ fmt.Fprintln(w, "}")
+
+ fmt.Fprintln(w)
+ fmt.Fprintf(w, "func %sTypes() []*types.Type {\n", name)
+ fmt.Fprintf(w, "var typs [%d]*types.Type\n", len(interner.typs))
+ for i, typ := range interner.typs {
+ fmt.Fprintf(w, "typs[%d] = %s\n", i, typ)
+ }
+ 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
+}
+
+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)
+ }
+ i.hash[x] = v
+ i.typs = append(i.typs, x)
+ }
+ 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 "types.Bytetype"
+ case "rune":
+ return "types.Runetype"
+ }
+ return fmt.Sprintf("types.Types[T%s]", strings.ToUpper(t.Name))
+ case *ast.SelectorExpr:
+ if t.X.(*ast.Ident).Name != "unsafe" || t.Sel.Name != "Pointer" {
+ log.Fatalf("unhandled type: %#v", t)
+ }
+ return "types.Types[TUNSAFEPTR]"
+
+ case *ast.ArrayType:
+ if t.Len == nil {
+ return fmt.Sprintf("types.NewSlice(%s)", i.subtype(t.Elt))
+ }
+ return fmt.Sprintf("types.NewArray(%s, %d)", i.subtype(t.Elt), intconst(t.Len))
+ case *ast.ChanType:
+ dir := "types.Cboth"
+ switch t.Dir {
+ case ast.SEND:
+ dir = "types.Csend"
+ case ast.RECV:
+ dir = "types.Crecv"
+ }
+ return fmt.Sprintf("types.NewChan(%s, %s)", i.subtype(t.Value), dir)
+ case *ast.FuncType:
+ return fmt.Sprintf("functype(nil, %s, %s)", i.fields(t.Params, false), i.fields(t.Results, false))
+ case *ast.InterfaceType:
+ if len(t.Methods.List) != 0 {
+ log.Fatal("non-empty interfaces unsupported")
+ }
+ return "types.Types[TINTER]"
+ case *ast.MapType:
+ return fmt.Sprintf("types.NewMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value))
+ case *ast.StarExpr:
+ return fmt.Sprintf("types.NewPtr(%s)", i.subtype(t.X))
+ case *ast.StructType:
+ return fmt.Sprintf("tostruct(%s)", i.fields(t.Fields, true))
+
+ default:
+ log.Fatalf("unhandled type: %#v", t)
+ panic("unreachable")
+ }
+}
+
+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, ", "))
+}
+
+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)
+ }
+ 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")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/mpfloat.go b/src/cmd/compile/internal/gc/mpfloat.go
new file mode 100644
index 0000000..401aef3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mpfloat.go
@@ -0,0 +1,357 @@
+// Copyright 2009 The Go Authors. 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"
+ "math"
+ "math/big"
+)
+
+// implements float arithmetic
+
+const (
+ // Maximum size in bits for Mpints before signalling
+ // overflow and also mantissa precision for Mpflts.
+ Mpprec = 512
+ // Turn on for constant arithmetic debugging output.
+ Mpdebug = false
+)
+
+// Mpflt represents a floating-point constant.
+type Mpflt struct {
+ Val big.Float
+}
+
+// Mpcplx represents a complex constant.
+type Mpcplx struct {
+ Real Mpflt
+ Imag Mpflt
+}
+
+// Use newMpflt (not new(Mpflt)!) to get the correct default precision.
+func newMpflt() *Mpflt {
+ var a Mpflt
+ a.Val.SetPrec(Mpprec)
+ return &a
+}
+
+// Use newMpcmplx (not new(Mpcplx)!) to get the correct default precision.
+func newMpcmplx() *Mpcplx {
+ var a Mpcplx
+ a.Real = *newMpflt()
+ a.Imag = *newMpflt()
+ return &a
+}
+
+func (a *Mpflt) SetInt(b *Mpint) {
+ if b.checkOverflow(0) {
+ // sign doesn't really matter but copy anyway
+ a.Val.SetInf(b.Val.Sign() < 0)
+ return
+ }
+ a.Val.SetInt(&b.Val)
+}
+
+func (a *Mpflt) Set(b *Mpflt) {
+ a.Val.Set(&b.Val)
+}
+
+func (a *Mpflt) Add(b *Mpflt) {
+ if Mpdebug {
+ fmt.Printf("\n%v + %v", a, b)
+ }
+
+ a.Val.Add(&a.Val, &b.Val)
+
+ if Mpdebug {
+ fmt.Printf(" = %v\n\n", a)
+ }
+}
+
+func (a *Mpflt) AddFloat64(c float64) {
+ var b Mpflt
+
+ b.SetFloat64(c)
+ a.Add(&b)
+}
+
+func (a *Mpflt) Sub(b *Mpflt) {
+ if Mpdebug {
+ fmt.Printf("\n%v - %v", a, b)
+ }
+
+ a.Val.Sub(&a.Val, &b.Val)
+
+ if Mpdebug {
+ fmt.Printf(" = %v\n\n", a)
+ }
+}
+
+func (a *Mpflt) Mul(b *Mpflt) {
+ if Mpdebug {
+ fmt.Printf("%v\n * %v\n", a, b)
+ }
+
+ a.Val.Mul(&a.Val, &b.Val)
+
+ if Mpdebug {
+ fmt.Printf(" = %v\n\n", a)
+ }
+}
+
+func (a *Mpflt) MulFloat64(c float64) {
+ var b Mpflt
+
+ b.SetFloat64(c)
+ a.Mul(&b)
+}
+
+func (a *Mpflt) Quo(b *Mpflt) {
+ if Mpdebug {
+ fmt.Printf("%v\n / %v\n", a, b)
+ }
+
+ a.Val.Quo(&a.Val, &b.Val)
+
+ if Mpdebug {
+ fmt.Printf(" = %v\n\n", a)
+ }
+}
+
+func (a *Mpflt) Cmp(b *Mpflt) int {
+ return a.Val.Cmp(&b.Val)
+}
+
+func (a *Mpflt) CmpFloat64(c float64) int {
+ if c == 0 {
+ return a.Val.Sign() // common case shortcut
+ }
+ return a.Val.Cmp(big.NewFloat(c))
+}
+
+func (a *Mpflt) Float64() float64 {
+ x, _ := a.Val.Float64()
+
+ // check for overflow
+ if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpflt Float64")
+ }
+
+ return x + 0 // avoid -0 (should not be needed, but be conservative)
+}
+
+func (a *Mpflt) Float32() float64 {
+ x32, _ := a.Val.Float32()
+ x := float64(x32)
+
+ // check for overflow
+ if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpflt Float32")
+ }
+
+ return x + 0 // avoid -0 (should not be needed, but be conservative)
+}
+
+func (a *Mpflt) SetFloat64(c float64) {
+ if Mpdebug {
+ fmt.Printf("\nconst %g", c)
+ }
+
+ // convert -0 to 0
+ if c == 0 {
+ c = 0
+ }
+ a.Val.SetFloat64(c)
+
+ if Mpdebug {
+ fmt.Printf(" = %v\n", a)
+ }
+}
+
+func (a *Mpflt) Neg() {
+ // avoid -0
+ if a.Val.Sign() != 0 {
+ a.Val.Neg(&a.Val)
+ }
+}
+
+func (a *Mpflt) SetString(as string) {
+ f, _, err := a.Val.Parse(as, 0)
+ if err != nil {
+ yyerror("malformed constant: %s (%v)", as, err)
+ a.Val.SetFloat64(0)
+ return
+ }
+
+ if f.IsInf() {
+ yyerror("constant too large: %s", as)
+ a.Val.SetFloat64(0)
+ return
+ }
+
+ // -0 becomes 0
+ if f.Sign() == 0 && f.Signbit() {
+ a.Val.SetFloat64(0)
+ }
+}
+
+func (f *Mpflt) String() string {
+ return f.Val.Text('b', 0)
+}
+
+func (fvp *Mpflt) GoString() string {
+ // determine sign
+ sign := ""
+ f := &fvp.Val
+ if f.Sign() < 0 {
+ sign = "-"
+ f = new(big.Float).Abs(f)
+ }
+
+ // Don't try to convert infinities (will not terminate).
+ if f.IsInf() {
+ return sign + "Inf"
+ }
+
+ // Use exact fmt formatting if in float64 range (common case):
+ // proceed if f doesn't underflow to 0 or overflow to inf.
+ if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) {
+ return fmt.Sprintf("%s%.6g", sign, x)
+ }
+
+ // Out of float64 range. Do approximate manual to decimal
+ // conversion to avoid precise but possibly slow Float
+ // formatting.
+ // f = mant * 2**exp
+ var mant big.Float
+ exp := f.MantExp(&mant) // 0.5 <= mant < 1.0
+
+ // approximate float64 mantissa m and decimal exponent d
+ // f ~ m * 10**d
+ m, _ := mant.Float64() // 0.5 <= m < 1.0
+ d := float64(exp) * (math.Ln2 / math.Ln10) // log_10(2)
+
+ // adjust m for truncated (integer) decimal exponent e
+ e := int64(d)
+ m *= math.Pow(10, d-float64(e))
+
+ // ensure 1 <= m < 10
+ switch {
+ case m < 1-0.5e-6:
+ // The %.6g format below rounds m to 5 digits after the
+ // decimal point. Make sure that m*10 < 10 even after
+ // rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6.
+ m *= 10
+ e--
+ case m >= 10:
+ m /= 10
+ e++
+ }
+
+ return fmt.Sprintf("%s%.6ge%+d", sign, m, e)
+}
+
+// complex multiply v *= rv
+// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
+func (v *Mpcplx) Mul(rv *Mpcplx) {
+ var ac, ad, bc, bd Mpflt
+
+ ac.Set(&v.Real)
+ ac.Mul(&rv.Real) // ac
+
+ bd.Set(&v.Imag)
+ bd.Mul(&rv.Imag) // bd
+
+ bc.Set(&v.Imag)
+ bc.Mul(&rv.Real) // bc
+
+ ad.Set(&v.Real)
+ ad.Mul(&rv.Imag) // ad
+
+ v.Real.Set(&ac)
+ v.Real.Sub(&bd) // ac-bd
+
+ v.Imag.Set(&bc)
+ v.Imag.Add(&ad) // bc+ad
+}
+
+// complex divide v /= rv
+// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
+func (v *Mpcplx) Div(rv *Mpcplx) bool {
+ if rv.Real.CmpFloat64(0) == 0 && rv.Imag.CmpFloat64(0) == 0 {
+ return false
+ }
+
+ var ac, ad, bc, bd, cc_plus_dd Mpflt
+
+ cc_plus_dd.Set(&rv.Real)
+ cc_plus_dd.Mul(&rv.Real) // cc
+
+ ac.Set(&rv.Imag)
+ ac.Mul(&rv.Imag) // dd
+ cc_plus_dd.Add(&ac) // cc+dd
+
+ // We already checked that c and d are not both zero, but we can't
+ // assume that c²+d² != 0 follows, because for tiny values of c
+ // and/or d c²+d² can underflow to zero. Check that c²+d² is
+ // nonzero, return if it's not.
+ if cc_plus_dd.CmpFloat64(0) == 0 {
+ return false
+ }
+
+ ac.Set(&v.Real)
+ ac.Mul(&rv.Real) // ac
+
+ bd.Set(&v.Imag)
+ bd.Mul(&rv.Imag) // bd
+
+ bc.Set(&v.Imag)
+ bc.Mul(&rv.Real) // bc
+
+ ad.Set(&v.Real)
+ ad.Mul(&rv.Imag) // ad
+
+ v.Real.Set(&ac)
+ v.Real.Add(&bd) // ac+bd
+ v.Real.Quo(&cc_plus_dd) // (ac+bd)/(cc+dd)
+
+ v.Imag.Set(&bc)
+ v.Imag.Sub(&ad) // bc-ad
+ v.Imag.Quo(&cc_plus_dd) // (bc+ad)/(cc+dd)
+
+ return true
+}
+
+func (v *Mpcplx) String() string {
+ return fmt.Sprintf("(%s+%si)", v.Real.String(), v.Imag.String())
+}
+
+func (v *Mpcplx) GoString() string {
+ var re string
+ sre := v.Real.CmpFloat64(0)
+ if sre != 0 {
+ re = v.Real.GoString()
+ }
+
+ var im string
+ sim := v.Imag.CmpFloat64(0)
+ if sim != 0 {
+ im = v.Imag.GoString()
+ }
+
+ switch {
+ case sre == 0 && sim == 0:
+ return "0"
+ case sre == 0:
+ return im + "i"
+ case sim == 0:
+ return re
+ case sim < 0:
+ return fmt.Sprintf("(%s%si)", re, im)
+ default:
+ return fmt.Sprintf("(%s+%si)", re, im)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/mpint.go b/src/cmd/compile/internal/gc/mpint.go
new file mode 100644
index 0000000..340350b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mpint.go
@@ -0,0 +1,304 @@
+// Copyright 2009 The Go Authors. 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"
+ "math/big"
+)
+
+// implements integer arithmetic
+
+// Mpint represents an integer constant.
+type Mpint struct {
+ Val big.Int
+ Ovf bool // set if Val overflowed compiler limit (sticky)
+ Rune bool // set if syntax indicates default type rune
+}
+
+func (a *Mpint) SetOverflow() {
+ a.Val.SetUint64(1) // avoid spurious div-zero errors
+ a.Ovf = true
+}
+
+func (a *Mpint) checkOverflow(extra int) bool {
+ // We don't need to be precise here, any reasonable upper limit would do.
+ // For now, use existing limit so we pass all the tests unchanged.
+ if a.Val.BitLen()+extra > Mpprec {
+ a.SetOverflow()
+ }
+ return a.Ovf
+}
+
+func (a *Mpint) Set(b *Mpint) {
+ a.Val.Set(&b.Val)
+}
+
+func (a *Mpint) SetFloat(b *Mpflt) bool {
+ // avoid converting huge floating-point numbers to integers
+ // (2*Mpprec is large enough to permit all tests to pass)
+ if b.Val.MantExp(nil) > 2*Mpprec {
+ a.SetOverflow()
+ return false
+ }
+
+ if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
+ return true
+ }
+
+ const delta = 16 // a reasonably small number of bits > 0
+ var t big.Float
+ t.SetPrec(Mpprec - delta)
+
+ // try rounding down a little
+ t.SetMode(big.ToZero)
+ t.Set(&b.Val)
+ if _, acc := t.Int(&a.Val); acc == big.Exact {
+ return true
+ }
+
+ // try rounding up a little
+ t.SetMode(big.AwayFromZero)
+ t.Set(&b.Val)
+ if _, acc := t.Int(&a.Val); acc == big.Exact {
+ return true
+ }
+
+ a.Ovf = false
+ return false
+}
+
+func (a *Mpint) Add(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Add")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.Add(&a.Val, &b.Val)
+
+ if a.checkOverflow(0) {
+ yyerror("constant addition overflow")
+ }
+}
+
+func (a *Mpint) Sub(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Sub")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.Sub(&a.Val, &b.Val)
+
+ if a.checkOverflow(0) {
+ yyerror("constant subtraction overflow")
+ }
+}
+
+func (a *Mpint) Mul(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Mul")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.Mul(&a.Val, &b.Val)
+
+ if a.checkOverflow(0) {
+ yyerror("constant multiplication overflow")
+ }
+}
+
+func (a *Mpint) Quo(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Quo")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.Quo(&a.Val, &b.Val)
+
+ if a.checkOverflow(0) {
+ // can only happen for div-0 which should be checked elsewhere
+ yyerror("constant division overflow")
+ }
+}
+
+func (a *Mpint) Rem(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Rem")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.Rem(&a.Val, &b.Val)
+
+ if a.checkOverflow(0) {
+ // should never happen
+ yyerror("constant modulo overflow")
+ }
+}
+
+func (a *Mpint) Or(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Or")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.Or(&a.Val, &b.Val)
+}
+
+func (a *Mpint) And(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint And")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.And(&a.Val, &b.Val)
+}
+
+func (a *Mpint) AndNot(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint AndNot")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.AndNot(&a.Val, &b.Val)
+}
+
+func (a *Mpint) Xor(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Xor")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ a.Val.Xor(&a.Val, &b.Val)
+}
+
+func (a *Mpint) Lsh(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Lsh")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ s := b.Int64()
+ if s < 0 || s >= Mpprec {
+ msg := "shift count too large"
+ if s < 0 {
+ msg = "invalid negative shift count"
+ }
+ yyerror("%s: %d", msg, s)
+ a.SetInt64(0)
+ return
+ }
+
+ if a.checkOverflow(int(s)) {
+ yyerror("constant shift overflow")
+ return
+ }
+ a.Val.Lsh(&a.Val, uint(s))
+}
+
+func (a *Mpint) Rsh(b *Mpint) {
+ if a.Ovf || b.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("ovf in Mpint Rsh")
+ }
+ a.SetOverflow()
+ return
+ }
+
+ s := b.Int64()
+ if s < 0 {
+ yyerror("invalid negative shift count: %d", s)
+ if a.Val.Sign() < 0 {
+ a.SetInt64(-1)
+ } else {
+ a.SetInt64(0)
+ }
+ return
+ }
+
+ a.Val.Rsh(&a.Val, uint(s))
+}
+
+func (a *Mpint) Cmp(b *Mpint) int {
+ return a.Val.Cmp(&b.Val)
+}
+
+func (a *Mpint) CmpInt64(c int64) int {
+ if c == 0 {
+ return a.Val.Sign() // common case shortcut
+ }
+ return a.Val.Cmp(big.NewInt(c))
+}
+
+func (a *Mpint) Neg() {
+ a.Val.Neg(&a.Val)
+}
+
+func (a *Mpint) Int64() int64 {
+ if a.Ovf {
+ if nsavederrors+nerrors == 0 {
+ Fatalf("constant overflow")
+ }
+ return 0
+ }
+
+ return a.Val.Int64()
+}
+
+func (a *Mpint) SetInt64(c int64) {
+ a.Val.SetInt64(c)
+}
+
+func (a *Mpint) SetString(as string) {
+ _, ok := a.Val.SetString(as, 0)
+ if !ok {
+ // The lexer checks for correct syntax of the literal
+ // and reports detailed errors. Thus SetString should
+ // never fail (in theory it might run out of memory,
+ // but that wouldn't be reported as an error here).
+ Fatalf("malformed integer constant: %s", as)
+ return
+ }
+ if a.checkOverflow(0) {
+ yyerror("constant too large: %s", as)
+ }
+}
+
+func (a *Mpint) GoString() string {
+ return a.Val.String()
+}
+
+func (a *Mpint) String() string {
+ return fmt.Sprintf("%#x", &a.Val)
+}
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
new file mode 100644
index 0000000..7494c3e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -0,0 +1,1756 @@
+// Copyright 2016 The Go Authors. 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"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "cmd/compile/internal/syntax"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+)
+
+// parseFiles concurrently parses files into *syntax.File structures.
+// Each declaration in every *syntax.File is converted to a syntax tree
+// and its root represented by *Node is appended to xtop.
+// Returns the total count of parsed lines.
+func parseFiles(filenames []string) uint {
+ noders := make([]*noder, 0, len(filenames))
+ // Limit the number of simultaneously open files.
+ sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
+
+ for _, filename := range filenames {
+ p := &noder{
+ basemap: make(map[*syntax.PosBase]*src.PosBase),
+ err: make(chan syntax.Error),
+ }
+ noders = append(noders, p)
+
+ go func(filename string) {
+ sem <- struct{}{}
+ defer func() { <-sem }()
+ defer close(p.err)
+ base := syntax.NewFileBase(filename)
+
+ f, err := os.Open(filename)
+ if err != nil {
+ p.error(syntax.Error{Msg: err.Error()})
+ return
+ }
+ defer f.Close()
+
+ p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error
+ }(filename)
+ }
+
+ var lines uint
+ for _, p := range noders {
+ for e := range p.err {
+ p.yyerrorpos(e.Pos, "%s", e.Msg)
+ }
+
+ p.node()
+ lines += p.file.Lines
+ p.file = nil // release memory
+
+ if nsyntaxerrors != 0 {
+ errorexit()
+ }
+ // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
+ testdclstack()
+ }
+
+ localpkg.Height = myheight
+
+ return lines
+}
+
+// makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase.
+func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
+ // fast path: most likely PosBase hasn't changed
+ if p.basecache.last == b0 {
+ return p.basecache.base
+ }
+
+ b1, ok := p.basemap[b0]
+ if !ok {
+ fn := b0.Filename()
+ if b0.IsFileBase() {
+ b1 = src.NewFileBase(fn, absFilename(fn))
+ } else {
+ // line directive base
+ p0 := b0.Pos()
+ p0b := p0.Base()
+ if p0b == b0 {
+ panic("infinite recursion in makeSrcPosBase")
+ }
+ p1 := src.MakePos(p.makeSrcPosBase(p0b), p0.Line(), p0.Col())
+ b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
+ }
+ p.basemap[b0] = b1
+ }
+
+ // update cache
+ p.basecache.last = b0
+ p.basecache.base = b1
+
+ return b1
+}
+
+func (p *noder) makeXPos(pos syntax.Pos) (_ src.XPos) {
+ return Ctxt.PosTable.XPos(src.MakePos(p.makeSrcPosBase(pos.Base()), pos.Line(), pos.Col()))
+}
+
+func (p *noder) yyerrorpos(pos syntax.Pos, format string, args ...interface{}) {
+ yyerrorl(p.makeXPos(pos), format, args...)
+}
+
+var pathPrefix string
+
+// TODO(gri) Can we eliminate fileh in favor of absFilename?
+func fileh(name string) string {
+ return objabi.AbsFile("", name, pathPrefix)
+}
+
+func absFilename(name string) string {
+ return objabi.AbsFile(Ctxt.Pathname, name, pathPrefix)
+}
+
+// noder transforms package syntax's AST into a Node tree.
+type noder struct {
+ basemap map[*syntax.PosBase]*src.PosBase
+ basecache struct {
+ last *syntax.PosBase
+ base *src.PosBase
+ }
+
+ file *syntax.File
+ linknames []linkname
+ pragcgobuf [][]string
+ err chan syntax.Error
+ scope ScopeID
+ importedUnsafe bool
+ importedEmbed bool
+
+ // scopeVars is a stack tracking the number of variables declared in the
+ // current function at the moment each open scope was opened.
+ scopeVars []int
+
+ lastCloseScopePos syntax.Pos
+}
+
+func (p *noder) funcBody(fn *Node, block *syntax.BlockStmt) {
+ oldScope := p.scope
+ p.scope = 0
+ funchdr(fn)
+
+ if block != nil {
+ body := p.stmts(block.List)
+ if body == nil {
+ body = []*Node{nod(OEMPTY, nil, nil)}
+ }
+ fn.Nbody.Set(body)
+
+ lineno = p.makeXPos(block.Rbrace)
+ fn.Func.Endlineno = lineno
+ }
+
+ funcbody()
+ p.scope = oldScope
+}
+
+func (p *noder) openScope(pos syntax.Pos) {
+ types.Markdcl()
+
+ if trackScopes {
+ Curfn.Func.Parents = append(Curfn.Func.Parents, p.scope)
+ p.scopeVars = append(p.scopeVars, len(Curfn.Func.Dcl))
+ p.scope = ScopeID(len(Curfn.Func.Parents))
+
+ p.markScope(pos)
+ }
+}
+
+func (p *noder) closeScope(pos syntax.Pos) {
+ p.lastCloseScopePos = pos
+ types.Popdcl()
+
+ if trackScopes {
+ scopeVars := p.scopeVars[len(p.scopeVars)-1]
+ p.scopeVars = p.scopeVars[:len(p.scopeVars)-1]
+ if scopeVars == len(Curfn.Func.Dcl) {
+ // no variables were declared in this scope, so we can retract it.
+
+ if int(p.scope) != len(Curfn.Func.Parents) {
+ Fatalf("scope tracking inconsistency, no variables declared but scopes were not retracted")
+ }
+
+ p.scope = Curfn.Func.Parents[p.scope-1]
+ Curfn.Func.Parents = Curfn.Func.Parents[:len(Curfn.Func.Parents)-1]
+
+ nmarks := len(Curfn.Func.Marks)
+ Curfn.Func.Marks[nmarks-1].Scope = p.scope
+ prevScope := ScopeID(0)
+ if nmarks >= 2 {
+ prevScope = Curfn.Func.Marks[nmarks-2].Scope
+ }
+ if Curfn.Func.Marks[nmarks-1].Scope == prevScope {
+ Curfn.Func.Marks = Curfn.Func.Marks[:nmarks-1]
+ }
+ return
+ }
+
+ p.scope = Curfn.Func.Parents[p.scope-1]
+
+ p.markScope(pos)
+ }
+}
+
+func (p *noder) markScope(pos syntax.Pos) {
+ xpos := p.makeXPos(pos)
+ if i := len(Curfn.Func.Marks); i > 0 && Curfn.Func.Marks[i-1].Pos == xpos {
+ Curfn.Func.Marks[i-1].Scope = p.scope
+ } else {
+ Curfn.Func.Marks = append(Curfn.Func.Marks, Mark{xpos, p.scope})
+ }
+}
+
+// closeAnotherScope is like closeScope, but it reuses the same mark
+// position as the last closeScope call. This is useful for "for" and
+// "if" statements, as their implicit blocks always end at the same
+// position as an explicit block.
+func (p *noder) closeAnotherScope() {
+ p.closeScope(p.lastCloseScopePos)
+}
+
+// linkname records a //go:linkname directive.
+type linkname struct {
+ pos syntax.Pos
+ local string
+ remote string
+}
+
+func (p *noder) node() {
+ types.Block = 1
+ p.importedUnsafe = false
+ p.importedEmbed = false
+
+ p.setlineno(p.file.PkgName)
+ mkpackage(p.file.PkgName.Value)
+
+ if pragma, ok := p.file.Pragma.(*Pragma); ok {
+ pragma.Flag &^= GoBuildPragma
+ p.checkUnused(pragma)
+ }
+
+ xtop = append(xtop, p.decls(p.file.DeclList)...)
+
+ for _, n := range p.linknames {
+ if !p.importedUnsafe {
+ p.yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
+ continue
+ }
+ s := lookup(n.local)
+ if n.remote != "" {
+ s.Linkname = n.remote
+ } else {
+ // Use the default object symbol name if the
+ // user didn't provide one.
+ if myimportpath == "" {
+ p.yyerrorpos(n.pos, "//go:linkname requires linkname argument or -p compiler flag")
+ } else {
+ s.Linkname = objabi.PathToPrefix(myimportpath) + "." + n.local
+ }
+ }
+ }
+
+ // The linker expects an ABI0 wrapper for all cgo-exported
+ // functions.
+ for _, prag := range p.pragcgobuf {
+ switch prag[0] {
+ case "cgo_export_static", "cgo_export_dynamic":
+ if symabiRefs == nil {
+ symabiRefs = make(map[string]obj.ABI)
+ }
+ symabiRefs[prag[1]] = obj.ABI0
+ }
+ }
+
+ pragcgobuf = append(pragcgobuf, p.pragcgobuf...)
+ lineno = src.NoXPos
+ clearImports()
+}
+
+func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
+ var cs constState
+
+ for _, decl := range decls {
+ p.setlineno(decl)
+ switch decl := decl.(type) {
+ case *syntax.ImportDecl:
+ p.importDecl(decl)
+
+ case *syntax.VarDecl:
+ l = append(l, p.varDecl(decl)...)
+
+ case *syntax.ConstDecl:
+ l = append(l, p.constDecl(decl, &cs)...)
+
+ 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) {
+ if imp.Path.Bad {
+ return // avoid follow-on errors if there was a syntax error
+ }
+
+ if pragma, ok := imp.Pragma.(*Pragma); ok {
+ p.checkUnused(pragma)
+ }
+
+ val := p.basicLit(imp.Path)
+ ipkg := importfile(&val)
+ if ipkg == nil {
+ if nerrors == 0 {
+ Fatalf("phase error in import")
+ }
+ return
+ }
+
+ if ipkg == unsafepkg {
+ p.importedUnsafe = true
+ }
+ if ipkg.Path == "embed" {
+ p.importedEmbed = true
+ }
+
+ ipkg.Direct = true
+
+ var my *types.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
+
+ switch my.Name {
+ case ".":
+ importdot(ipkg, pack)
+ return
+ case "init":
+ yyerrorl(pack.Pos, "cannot import package as init - init must be a func")
+ return
+ case "_":
+ return
+ }
+ if my.Def != nil {
+ redeclare(pack.Pos, my, "as imported package name")
+ }
+ my.Def = asTypesNode(pack)
+ my.Lastlineno = pack.Pos
+ my.Block = 1 // at top level
+}
+
+func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
+ names := p.declNames(decl.NameList)
+ typ := p.typeExprOrNil(decl.Type)
+
+ var exprs []*Node
+ if decl.Values != nil {
+ exprs = p.exprList(decl.Values)
+ }
+
+ if pragma, ok := decl.Pragma.(*Pragma); ok {
+ if len(pragma.Embeds) > 0 {
+ if !p.importedEmbed {
+ // This check can't be done when building the list pragma.Embeds
+ // because that list is created before the noder starts walking over the file,
+ // so at that point it hasn't seen the imports.
+ // We're left to check now, just before applying the //go:embed lines.
+ for _, e := range pragma.Embeds {
+ p.yyerrorpos(e.Pos, "//go:embed only allowed in Go files that import \"embed\"")
+ }
+ } else {
+ varEmbed(p, names, typ, exprs, pragma.Embeds)
+ }
+ pragma.Embeds = nil
+ }
+ p.checkUnused(pragma)
+ }
+
+ p.setlineno(decl)
+ return variter(names, typ, exprs)
+}
+
+// constState tracks state between constant specifiers within a
+// declaration group. This state is kept separate from noder so nested
+// constant declarations are handled correctly (e.g., issue 15550).
+type constState struct {
+ group *syntax.Group
+ typ *Node
+ values []*Node
+ iota int64
+}
+
+func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []*Node {
+ if decl.Group == nil || decl.Group != cs.group {
+ *cs = constState{
+ group: decl.Group,
+ }
+ }
+
+ if pragma, ok := decl.Pragma.(*Pragma); ok {
+ p.checkUnused(pragma)
+ }
+
+ names := p.declNames(decl.NameList)
+ typ := p.typeExprOrNil(decl.Type)
+
+ var values []*Node
+ if decl.Values != nil {
+ values = p.exprList(decl.Values)
+ cs.typ, cs.values = typ, values
+ } else {
+ if typ != nil {
+ yyerror("const declaration cannot have type without expression")
+ }
+ typ, values = cs.typ, cs.values
+ }
+
+ nn := make([]*Node, 0, len(names))
+ for i, n := range names {
+ if i >= len(values) {
+ yyerror("missing value in const declaration")
+ break
+ }
+ v := values[i]
+ if decl.Values == nil {
+ v = treecopy(v, n.Pos)
+ }
+
+ n.Op = OLITERAL
+ declare(n, dclcontext)
+
+ n.Name.Param.Ntype = typ
+ n.Name.Defn = v
+ n.SetIota(cs.iota)
+
+ nn = append(nn, p.nod(decl, ODCLCONST, n, nil))
+ }
+
+ if len(values) > len(names) {
+ yyerror("extra expression in const declaration")
+ }
+
+ cs.iota++
+
+ return nn
+}
+
+func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
+ n := p.declName(decl.Name)
+ n.Op = OTYPE
+ declare(n, dclcontext)
+
+ // decl.Type may be nil but in that case we got a syntax error during parsing
+ typ := p.typeExprOrNil(decl.Type)
+
+ param := n.Name.Param
+ param.Ntype = typ
+ param.SetAlias(decl.Alias)
+ if pragma, ok := decl.Pragma.(*Pragma); ok {
+ if !decl.Alias {
+ param.SetPragma(pragma.Flag & TypePragmas)
+ pragma.Flag &^= TypePragmas
+ }
+ p.checkUnused(pragma)
+ }
+
+ nod := p.nod(decl, ODCLTYPE, n, nil)
+ if param.Alias() && !langSupported(1, 9, localpkg) {
+ yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9")
+ }
+ return nod
+}
+
+func (p *noder) declNames(names []*syntax.Name) []*Node {
+ nodes := make([]*Node, 0, len(names))
+ for _, name := range names {
+ nodes = append(nodes, p.declName(name))
+ }
+ return nodes
+}
+
+func (p *noder) declName(name *syntax.Name) *Node {
+ n := dclname(p.name(name))
+ n.Pos = p.pos(name)
+ return n
+}
+
+func (p *noder) funcDecl(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 {
+ if name.Name == "init" {
+ name = renameinit()
+ if t.List.Len() > 0 || t.Rlist.Len() > 0 {
+ yyerrorl(f.Pos, "func init must have no arguments and no return values")
+ }
+ }
+
+ if localpkg.Name == "main" && name.Name == "main" {
+ if t.List.Len() > 0 || t.Rlist.Len() > 0 {
+ yyerrorl(f.Pos, "func main must have no arguments and no return values")
+ }
+ }
+ } else {
+ f.Func.Shortname = name
+ name = nblank.Sym // filled in by typecheckfunc
+ }
+
+ f.Func.Nname = newfuncnamel(p.pos(fun.Name), name)
+ f.Func.Nname.Name.Defn = f
+ f.Func.Nname.Name.Param.Ntype = t
+
+ if pragma, ok := fun.Pragma.(*Pragma); ok {
+ f.Func.Pragma = pragma.Flag & FuncPragmas
+ if pragma.Flag&Systemstack != 0 && pragma.Flag&Nosplit != 0 {
+ yyerrorl(f.Pos, "go:nosplit and go:systemstack cannot be combined")
+ }
+ pragma.Flag &^= FuncPragmas
+ p.checkUnused(pragma)
+ }
+
+ if fun.Recv == nil {
+ declare(f.Func.Nname, PFUNC)
+ }
+
+ p.funcBody(f, fun.Body)
+
+ if fun.Body != nil {
+ if f.Func.Pragma&Noescape != 0 {
+ yyerrorl(f.Pos, "can only use //go:noescape with external func implementations")
+ }
+ } else {
+ if pure_go || strings.HasPrefix(f.funcname(), "init.") {
+ // Linknamed functions are allowed to have no body. Hopefully
+ // the linkname target has a body. See issue 23311.
+ isLinknamed := false
+ for _, n := range p.linknames {
+ if f.funcname() == n.local {
+ isLinknamed = true
+ break
+ }
+ }
+ if !isLinknamed {
+ yyerrorl(f.Pos, "missing function body")
+ }
+ }
+ }
+
+ 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 {
+ nodes := make([]*Node, 0, len(params))
+ for i, param := range params {
+ p.setlineno(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 *types.Sym
+ if param.Name != nil {
+ name = p.name(param.Name)
+ }
+
+ typ := p.typeExpr(param.Type)
+ n := p.nodSym(param, ODCLFIELD, typ, name)
+
+ // rewrite ...T parameter
+ if typ.Op == ODDD {
+ if !dddOk {
+ // We mark these as syntax errors to get automatic elimination
+ // of multiple such errors per line (see yyerrorl in subr.go).
+ yyerror("syntax error: cannot use ... in receiver or result parameter list")
+ } else if !final {
+ if param.Name == nil {
+ yyerror("syntax error: cannot use ... with non-final parameter")
+ } else {
+ p.yyerrorpos(param.Name.Pos(), "syntax error: cannot use ... with non-final parameter %s", param.Name.Value)
+ }
+ }
+ typ.Op = OTARRAY
+ typ.Right = typ.Left
+ typ.Left = nil
+ n.SetIsDDD(true)
+ if n.Left != nil {
+ n.Left.SetIsDDD(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 {
+ nodes := make([]*Node, 0, len(exprs))
+ for _, expr := range exprs {
+ nodes = append(nodes, p.expr(expr))
+ }
+ return nodes
+}
+
+func (p *noder) expr(expr syntax.Expr) *Node {
+ p.setlineno(expr)
+ switch expr := expr.(type) {
+ case nil, *syntax.BadExpr:
+ return nil
+ case *syntax.Name:
+ return p.mkname(expr)
+ case *syntax.BasicLit:
+ n := nodlit(p.basicLit(expr))
+ n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error
+ return n
+ 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.makeXPos(expr.Rbrace)
+ return n
+ case *syntax.KeyValueExpr:
+ // use position of expr.Key rather than of expr (which has position of ':')
+ return p.nod(expr.Key, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
+ case *syntax.FuncLit:
+ return p.funcLit(expr)
+ case *syntax.ParenExpr:
+ return p.nod(expr, OPAREN, p.expr(expr.X), nil)
+ case *syntax.SelectorExpr:
+ // parser.new_dotname
+ obj := p.expr(expr.X)
+ if obj.Op == OPACK {
+ obj.Name.SetUsed(true)
+ return importName(obj.Name.Pkg.Lookup(expr.Sel.Value))
+ }
+ n := nodSym(OXDOT, obj, p.name(expr.Sel))
+ n.Pos = p.pos(expr) // lineno may have been changed by p.expr(expr.X)
+ return n
+ 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:
+ return p.nod(expr, ODOTTYPE, p.expr(expr.X), p.typeExpr(expr.Type))
+ case *syntax.Operation:
+ if expr.Op == syntax.Add && expr.Y != nil {
+ return p.sum(expr)
+ }
+ x := p.expr(expr.X)
+ if expr.Y == nil {
+ 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.SetIsDDD(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.SetTChanDir(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 n.Left.isBlank() {
+ yyerror("invalid variable name %v in type switch", n.Left)
+ }
+ }
+ return n
+ }
+ panic("unhandled Expr")
+}
+
+// sum efficiently handles very large summation expressions (such as
+// in issue #16394). In particular, it avoids left recursion and
+// collapses string literals.
+func (p *noder) sum(x syntax.Expr) *Node {
+ // While we need to handle long sums with asymptotic
+ // efficiency, the vast majority of sums are very small: ~95%
+ // have only 2 or 3 operands, and ~99% of string literals are
+ // never concatenated.
+
+ adds := make([]*syntax.Operation, 0, 2)
+ for {
+ add, ok := x.(*syntax.Operation)
+ if !ok || add.Op != syntax.Add || add.Y == nil {
+ break
+ }
+ adds = append(adds, add)
+ x = add.X
+ }
+
+ // nstr is the current rightmost string literal in the
+ // summation (if any), and chunks holds its accumulated
+ // substrings.
+ //
+ // Consider the expression x + "a" + "b" + "c" + y. When we
+ // reach the string literal "a", we assign nstr to point to
+ // its corresponding Node and initialize chunks to {"a"}.
+ // Visiting the subsequent string literals "b" and "c", we
+ // simply append their values to chunks. Finally, when we
+ // reach the non-constant operand y, we'll join chunks to form
+ // "abc" and reassign the "a" string literal's value.
+ //
+ // N.B., we need to be careful about named string constants
+ // (indicated by Sym != nil) because 1) we can't modify their
+ // value, as doing so would affect other uses of the string
+ // constant, and 2) they may have types, which we need to
+ // handle correctly. For now, we avoid these problems by
+ // treating named string constants the same as non-constant
+ // operands.
+ var nstr *Node
+ chunks := make([]string, 0, 1)
+
+ n := p.expr(x)
+ if Isconst(n, CTSTR) && n.Sym == nil {
+ nstr = n
+ chunks = append(chunks, nstr.StringVal())
+ }
+
+ for i := len(adds) - 1; i >= 0; i-- {
+ add := adds[i]
+
+ r := p.expr(add.Y)
+ if Isconst(r, CTSTR) && r.Sym == nil {
+ if nstr != nil {
+ // Collapse r into nstr instead of adding to n.
+ chunks = append(chunks, r.StringVal())
+ continue
+ }
+
+ nstr = r
+ chunks = append(chunks, nstr.StringVal())
+ } else {
+ if len(chunks) > 1 {
+ nstr.SetVal(Val{U: strings.Join(chunks, "")})
+ }
+ nstr = nil
+ chunks = chunks[:0]
+ }
+ n = p.nod(add, OADD, n, r)
+ }
+ if len(chunks) > 1 {
+ nstr.SetVal(Val{U: strings.Join(chunks, "")})
+ }
+
+ return n
+}
+
+func (p *noder) typeExpr(typ syntax.Expr) *Node {
+ // TODO(mdempsky): Be stricter? typecheck should handle errors anyway.
+ return p.expr(typ)
+}
+
+func (p *noder) typeExprOrNil(typ syntax.Expr) *Node {
+ if typ != nil {
+ return p.expr(typ)
+ }
+ return nil
+}
+
+func (p *noder) chanDir(dir syntax.ChanDir) types.ChanDir {
+ switch dir {
+ case 0:
+ return types.Cboth
+ case syntax.SendOnly:
+ return types.Csend
+ case syntax.RecvOnly:
+ return types.Crecv
+ }
+ panic("unhandled ChanDir")
+}
+
+func (p *noder) structType(expr *syntax.StructType) *Node {
+ l := make([]*Node, 0, len(expr.FieldList))
+ for i, field := range expr.FieldList {
+ p.setlineno(field)
+ var n *Node
+ if field.Name == nil {
+ n = p.embedded(field.Type)
+ } else {
+ n = p.nodSym(field, ODCLFIELD, p.typeExpr(field.Type), p.name(field.Name))
+ }
+ if i < len(expr.TagList) && expr.TagList[i] != nil {
+ n.SetVal(p.basicLit(expr.TagList[i]))
+ }
+ l = append(l, n)
+ }
+
+ p.setlineno(expr)
+ n := p.nod(expr, OTSTRUCT, nil, nil)
+ n.List.Set(l)
+ return n
+}
+
+func (p *noder) interfaceType(expr *syntax.InterfaceType) *Node {
+ l := make([]*Node, 0, len(expr.MethodList))
+ for _, method := range expr.MethodList {
+ p.setlineno(method)
+ var n *Node
+ if method.Name == nil {
+ n = p.nodSym(method, ODCLFIELD, importName(p.packname(method.Type)), nil)
+ } else {
+ mname := p.name(method.Name)
+ sig := p.typeExpr(method.Type)
+ sig.Left = fakeRecv()
+ n = p.nodSym(method, ODCLFIELD, sig, mname)
+ 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) *types.Sym {
+ switch expr := expr.(type) {
+ case *syntax.Name:
+ name := p.name(expr)
+ if n := oldname(name); n.Name != nil && n.Name.Pack != nil {
+ n.Name.Pack.Name.SetUsed(true)
+ }
+ return name
+ case *syntax.SelectorExpr:
+ name := p.name(expr.X.(*syntax.Name))
+ def := asNode(name.Def)
+ if def == nil {
+ yyerror("undefined: %v", name)
+ return name
+ }
+ var pkg *types.Pkg
+ if def.Op != OPACK {
+ yyerror("%v is not a package", name)
+ pkg = localpkg
+ } else {
+ def.Name.SetUsed(true)
+ pkg = def.Name.Pkg
+ }
+ return pkg.Lookup(expr.Sel.Value)
+ }
+ 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
+ }
+
+ sym := p.packname(typ)
+ n := p.nodSym(typ, ODCLFIELD, importName(sym), lookup(sym.Name))
+ n.SetEmbedded(true)
+
+ if isStar {
+ n.Left = p.nod(op, ODEREF, n.Left, nil)
+ }
+ return n
+}
+
+func (p *noder) stmts(stmts []syntax.Stmt) []*Node {
+ return p.stmtsFall(stmts, false)
+}
+
+func (p *noder) stmtsFall(stmts []syntax.Stmt, fallOK bool) []*Node {
+ var nodes []*Node
+ for i, stmt := range stmts {
+ s := p.stmtFall(stmt, fallOK && i+1 == len(stmts))
+ 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 {
+ return p.stmtFall(stmt, false)
+}
+
+func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
+ p.setlineno(stmt)
+ switch stmt := stmt.(type) {
+ case *syntax.EmptyStmt:
+ return nil
+ case *syntax.LabeledStmt:
+ return p.labeledStmt(stmt, fallOK)
+ case *syntax.BlockStmt:
+ l := p.blockStmt(stmt)
+ if len(l) == 0 {
+ // TODO(mdempsky): Line number?
+ return nod(OEMPTY, nil, nil)
+ }
+ return liststmt(l)
+ case *syntax.ExprStmt:
+ return p.wrapname(stmt, p.expr(stmt.X))
+ case *syntax.SendStmt:
+ 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.SetImplicit(stmt.Rhs == syntax.ImplicitOne)
+ n.SetSubOp(p.binOp(stmt.Op))
+ return n
+ }
+
+ n := p.nod(stmt, OAS, nil, nil) // assume common case
+
+ rhs := p.exprList(stmt.Rhs)
+ lhs := p.assignList(stmt.Lhs, n, stmt.Op == syntax.Def)
+
+ 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:
+ if !fallOK {
+ yyerror("fallthrough statement out of place")
+ }
+ op = OFALL
+ case syntax.Goto:
+ op = OGOTO
+ default:
+ panic("unhandled BranchStmt")
+ }
+ n := p.nod(stmt, op, nil, nil)
+ if stmt.Label != nil {
+ n.Sym = p.name(stmt.Label)
+ }
+ return n
+ case *syntax.CallStmt:
+ var op Op
+ switch stmt.Tok {
+ case syntax.Defer:
+ op = ODEFER
+ case syntax.Go:
+ op = OGO
+ 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 asNode(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) assignList(expr syntax.Expr, defn *Node, colas bool) []*Node {
+ if !colas {
+ return p.exprList(expr)
+ }
+
+ defn.SetColas(true)
+
+ var exprs []syntax.Expr
+ if list, ok := expr.(*syntax.ListExpr); ok {
+ exprs = list.ElemList
+ } else {
+ exprs = []syntax.Expr{expr}
+ }
+
+ res := make([]*Node, len(exprs))
+ seen := make(map[*types.Sym]bool, len(exprs))
+
+ newOrErr := false
+ for i, expr := range exprs {
+ p.setlineno(expr)
+ res[i] = nblank
+
+ name, ok := expr.(*syntax.Name)
+ if !ok {
+ p.yyerrorpos(expr.Pos(), "non-name %v on left side of :=", p.expr(expr))
+ newOrErr = true
+ continue
+ }
+
+ sym := p.name(name)
+ if sym.IsBlank() {
+ continue
+ }
+
+ if seen[sym] {
+ p.yyerrorpos(expr.Pos(), "%v repeated on left side of :=", sym)
+ newOrErr = true
+ continue
+ }
+ seen[sym] = true
+
+ if sym.Block == types.Block {
+ res[i] = oldname(sym)
+ continue
+ }
+
+ newOrErr = true
+ n := newname(sym)
+ declare(n, dclcontext)
+ n.Name.Defn = defn
+ defn.Ninit.Append(nod(ODCL, n, nil))
+ res[i] = n
+ }
+
+ if !newOrErr {
+ yyerrorl(defn.Pos, "no new variables on left side of :=")
+ }
+ return res
+}
+
+func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
+ p.openScope(stmt.Pos())
+ nodes := p.stmts(stmt.List)
+ p.closeScope(stmt.Rbrace)
+ return nodes
+}
+
+func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
+ p.openScope(stmt.Pos())
+ 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.blockStmt(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)
+ }
+ }
+ p.closeAnotherScope()
+ return n
+}
+
+func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
+ p.openScope(stmt.Pos())
+ 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 {
+ n.List.Set(p.assignList(r.Lhs, n, r.Def))
+ }
+ } 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.blockStmt(stmt.Body))
+ p.closeAnotherScope()
+ return n
+}
+
+func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
+ p.openScope(stmt.Pos())
+ 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 = nil
+ }
+ n.List.Set(p.caseClauses(stmt.Body, tswitch, stmt.Rbrace))
+
+ p.closeScope(stmt.Rbrace)
+ return n
+}
+
+func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node, rbrace syntax.Pos) []*Node {
+ nodes := make([]*Node, 0, len(clauses))
+ for i, clause := range clauses {
+ p.setlineno(clause)
+ if i > 0 {
+ p.closeScope(clause.Pos())
+ }
+ p.openScope(clause.Pos())
+
+ n := p.nod(clause, OCASE, nil, nil)
+ if clause.Cases != nil {
+ n.List.Set(p.exprList(clause.Cases))
+ }
+ if tswitch != nil && tswitch.Left != 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
+ }
+
+ // Trim trailing empty statements. We omit them from
+ // the Node AST anyway, and it's easier to identify
+ // out-of-place fallthrough statements without them.
+ body := clause.Body
+ for len(body) > 0 {
+ if _, ok := body[len(body)-1].(*syntax.EmptyStmt); !ok {
+ break
+ }
+ body = body[:len(body)-1]
+ }
+
+ n.Nbody.Set(p.stmtsFall(body, true))
+ if l := n.Nbody.Len(); l > 0 && n.Nbody.Index(l-1).Op == OFALL {
+ if tswitch != nil {
+ yyerror("cannot fallthrough in type switch")
+ }
+ if i+1 == len(clauses) {
+ yyerror("cannot fallthrough final case in switch")
+ }
+ }
+
+ nodes = append(nodes, n)
+ }
+ if len(clauses) > 0 {
+ p.closeScope(rbrace)
+ }
+ return nodes
+}
+
+func (p *noder) selectStmt(stmt *syntax.SelectStmt) *Node {
+ n := p.nod(stmt, OSELECT, nil, nil)
+ n.List.Set(p.commClauses(stmt.Body, stmt.Rbrace))
+ return n
+}
+
+func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []*Node {
+ nodes := make([]*Node, 0, len(clauses))
+ for i, clause := range clauses {
+ p.setlineno(clause)
+ if i > 0 {
+ p.closeScope(clause.Pos())
+ }
+ p.openScope(clause.Pos())
+
+ n := p.nod(clause, OCASE, nil, nil)
+ if clause.Comm != nil {
+ n.List.Set1(p.stmt(clause.Comm))
+ }
+ n.Nbody.Set(p.stmts(clause.Body))
+ nodes = append(nodes, n)
+ }
+ if len(clauses) > 0 {
+ p.closeScope(rbrace)
+ }
+ return nodes
+}
+
+func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) *Node {
+ lhs := p.nodSym(label, OLABEL, nil, p.name(label.Label))
+
+ var ls *Node
+ if label.Stmt != nil { // TODO(mdempsky): Should always be present.
+ ls = p.stmtFall(label.Stmt, fallOK)
+ }
+
+ 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: ODEREF,
+ syntax.And: OADDR,
+
+ syntax.Not: ONOT,
+ syntax.Xor: OBITNOT,
+ syntax.Add: OPLUS,
+ syntax.Sub: ONEG,
+}
+
+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]
+}
+
+// checkLangCompat reports an error if the representation of a numeric
+// literal is not compatible with the current language version.
+func checkLangCompat(lit *syntax.BasicLit) {
+ s := lit.Value
+ if len(s) <= 2 || langSupported(1, 13, localpkg) {
+ return
+ }
+ // len(s) > 2
+ if strings.Contains(s, "_") {
+ yyerrorv("go1.13", "underscores in numeric literals")
+ return
+ }
+ if s[0] != '0' {
+ return
+ }
+ base := s[1]
+ if base == 'b' || base == 'B' {
+ yyerrorv("go1.13", "binary literals")
+ return
+ }
+ if base == 'o' || base == 'O' {
+ yyerrorv("go1.13", "0o/0O-style octal literals")
+ return
+ }
+ if lit.Kind != syntax.IntLit && (base == 'x' || base == 'X') {
+ yyerrorv("go1.13", "hexadecimal floating-point literals")
+ }
+}
+
+func (p *noder) basicLit(lit *syntax.BasicLit) Val {
+ // We don't use the errors of the conversion routines to determine
+ // if a literal string is valid because the conversion routines may
+ // accept a wider syntax than the language permits. Rely on lit.Bad
+ // instead.
+ switch s := lit.Value; lit.Kind {
+ case syntax.IntLit:
+ checkLangCompat(lit)
+ x := new(Mpint)
+ if !lit.Bad {
+ x.SetString(s)
+ }
+ return Val{U: x}
+
+ case syntax.FloatLit:
+ checkLangCompat(lit)
+ x := newMpflt()
+ if !lit.Bad {
+ x.SetString(s)
+ }
+ return Val{U: x}
+
+ case syntax.ImagLit:
+ checkLangCompat(lit)
+ x := newMpcmplx()
+ if !lit.Bad {
+ x.Imag.SetString(strings.TrimSuffix(s, "i"))
+ }
+ return Val{U: x}
+
+ case syntax.RuneLit:
+ x := new(Mpint)
+ x.Rune = true
+ if !lit.Bad {
+ u, _ := strconv.Unquote(s)
+ var r rune
+ if len(u) == 1 {
+ r = rune(u[0])
+ } else {
+ r, _ = utf8.DecodeRuneInString(u)
+ }
+ x.SetInt64(int64(r))
+ }
+ return Val{U: x}
+
+ case syntax.StringLit:
+ var x string
+ if !lit.Bad {
+ if len(s) > 0 && s[0] == '`' {
+ // strip carriage returns from raw string
+ s = strings.Replace(s, "\r", "", -1)
+ }
+ x, _ = strconv.Unquote(s)
+ }
+ return Val{U: x}
+
+ default:
+ panic("unhandled BasicLit kind")
+ }
+}
+
+func (p *noder) name(name *syntax.Name) *types.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) 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.SetImplicit(true)
+ }
+ return x
+}
+
+func (p *noder) nod(orig syntax.Node, op Op, left, right *Node) *Node {
+ return nodl(p.pos(orig), op, left, right)
+}
+
+func (p *noder) nodSym(orig syntax.Node, op Op, left *Node, sym *types.Sym) *Node {
+ n := nodSym(op, left, sym)
+ n.Pos = p.pos(orig)
+ return n
+}
+
+func (p *noder) pos(n syntax.Node) src.XPos {
+ // TODO(gri): orig.Pos() should always be known - fix package syntax
+ xpos := lineno
+ if pos := n.Pos(); pos.IsKnown() {
+ xpos = p.makeXPos(pos)
+ }
+ return xpos
+}
+
+func (p *noder) setlineno(n syntax.Node) {
+ if n != nil {
+ lineno = p.pos(n)
+ }
+}
+
+// error is called concurrently if files are parsed concurrently.
+func (p *noder) error(err error) {
+ p.err <- err.(syntax.Error)
+}
+
+// pragmas that are allowed in the std lib, but don't have
+// a syntax.Pragma value (see lex.go) associated with them.
+var allowedStdPragmas = map[string]bool{
+ "go:cgo_export_static": true,
+ "go:cgo_export_dynamic": true,
+ "go:cgo_import_static": true,
+ "go:cgo_import_dynamic": true,
+ "go:cgo_ldflag": true,
+ "go:cgo_dynamic_linker": true,
+ "go:embed": true,
+ "go:generate": true,
+}
+
+// *Pragma is the value stored in a syntax.Pragma during parsing.
+type Pragma struct {
+ Flag PragmaFlag // collected bits
+ Pos []PragmaPos // position of each individual flag
+ Embeds []PragmaEmbed
+}
+
+type PragmaPos struct {
+ Flag PragmaFlag
+ Pos syntax.Pos
+}
+
+type PragmaEmbed struct {
+ Pos syntax.Pos
+ Patterns []string
+}
+
+func (p *noder) checkUnused(pragma *Pragma) {
+ for _, pos := range pragma.Pos {
+ if pos.Flag&pragma.Flag != 0 {
+ p.yyerrorpos(pos.Pos, "misplaced compiler directive")
+ }
+ }
+ if len(pragma.Embeds) > 0 {
+ for _, e := range pragma.Embeds {
+ p.yyerrorpos(e.Pos, "misplaced go:embed directive")
+ }
+ }
+}
+
+func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
+ for _, pos := range pragma.Pos {
+ if pos.Flag&pragma.Flag != 0 {
+ p.error(syntax.Error{Pos: pos.Pos, Msg: "misplaced compiler directive"})
+ }
+ }
+ if len(pragma.Embeds) > 0 {
+ for _, e := range pragma.Embeds {
+ p.error(syntax.Error{Pos: e.Pos, Msg: "misplaced go:embed directive"})
+ }
+ }
+}
+
+// pragma is called concurrently if files are parsed concurrently.
+func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.Pragma) syntax.Pragma {
+ pragma, _ := old.(*Pragma)
+ if pragma == nil {
+ pragma = new(Pragma)
+ }
+
+ if text == "" {
+ // unused pragma; only called with old != nil.
+ p.checkUnusedDuringParse(pragma)
+ return nil
+ }
+
+ if strings.HasPrefix(text, "line ") {
+ // line directives are handled by syntax package
+ panic("unreachable")
+ }
+
+ if !blankLine {
+ // directive must be on line by itself
+ p.error(syntax.Error{Pos: pos, Msg: "misplaced compiler directive"})
+ return pragma
+ }
+
+ switch {
+ case strings.HasPrefix(text, "go:linkname "):
+ f := strings.Fields(text)
+ if !(2 <= len(f) && len(f) <= 3) {
+ p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname [linkname]"})
+ break
+ }
+ // The second argument is optional. If omitted, we use
+ // the default object symbol name for this and
+ // linkname only serves to mark this symbol as
+ // something that may be referenced via the object
+ // symbol name from another package.
+ var target string
+ if len(f) == 3 {
+ target = f[2]
+ }
+ p.linknames = append(p.linknames, linkname{pos, f[1], target})
+
+ case text == "go:embed", strings.HasPrefix(text, "go:embed "):
+ args, err := parseGoEmbed(text[len("go:embed"):])
+ if err != nil {
+ p.error(syntax.Error{Pos: pos, Msg: err.Error()})
+ }
+ if len(args) == 0 {
+ p.error(syntax.Error{Pos: pos, Msg: "usage: //go:embed pattern..."})
+ break
+ }
+ pragma.Embeds = append(pragma.Embeds, PragmaEmbed{pos, args})
+
+ case strings.HasPrefix(text, "go:cgo_import_dynamic "):
+ // This is permitted for general use because Solaris
+ // code relies on it in golang.org/x/sys/unix and others.
+ fields := pragmaFields(text)
+ if len(fields) >= 4 {
+ lib := strings.Trim(fields[3], `"`)
+ if lib != "" && !safeArg(lib) && !isCgoGeneratedFile(pos) {
+ p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("invalid library name %q in cgo_import_dynamic directive", lib)})
+ }
+ p.pragcgo(pos, text)
+ pragma.Flag |= pragmaFlag("go:cgo_import_dynamic")
+ break
+ }
+ fallthrough
+ case strings.HasPrefix(text, "go:cgo_"):
+ // For security, we disallow //go:cgo_* directives other
+ // than cgo_import_dynamic outside cgo-generated files.
+ // Exception: they are allowed in the standard library, for runtime and syscall.
+ if !isCgoGeneratedFile(pos) && !compiling_std {
+ p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)})
+ }
+ p.pragcgo(pos, text)
+ fallthrough // because of //go:cgo_unsafe_args
+ default:
+ verb := text
+ if i := strings.Index(text, " "); i >= 0 {
+ verb = verb[:i]
+ }
+ flag := pragmaFlag(verb)
+ const runtimePragmas = Systemstack | Nowritebarrier | Nowritebarrierrec | Yeswritebarrierrec
+ if !compiling_runtime && flag&runtimePragmas != 0 {
+ p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in runtime", verb)})
+ }
+ if flag == 0 && !allowedStdPragmas[verb] && compiling_std {
+ p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s is not allowed in the standard library", verb)})
+ }
+ pragma.Flag |= flag
+ pragma.Pos = append(pragma.Pos, PragmaPos{flag, pos})
+ }
+
+ return pragma
+}
+
+// isCgoGeneratedFile reports whether pos is in a file
+// generated by cgo, which is to say a file with name
+// beginning with "_cgo_". Such files are allowed to
+// contain cgo directives, and for security reasons
+// (primarily misuse of linker flags), other files are not.
+// See golang.org/issue/23672.
+func isCgoGeneratedFile(pos syntax.Pos) bool {
+ return strings.HasPrefix(filepath.Base(filepath.Clean(fileh(pos.Base().Filename()))), "_cgo_")
+}
+
+// safeArg reports whether arg is a "safe" command-line argument,
+// meaning that when it appears in a command-line, it probably
+// doesn't have some special meaning other than its own name.
+// This is copied from SafeArg in cmd/go/internal/load/pkg.go.
+func safeArg(name string) bool {
+ if name == "" {
+ return false
+ }
+ c := name[0]
+ return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
+}
+
+func mkname(sym *types.Sym) *Node {
+ n := oldname(sym)
+ if n.Name != nil && n.Name.Pack != nil {
+ n.Name.Pack.Name.SetUsed(true)
+ }
+ return n
+}
+
+// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
+// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
+// go/build/read.go also processes these strings and contains similar logic.
+func parseGoEmbed(args string) ([]string, error) {
+ var list []string
+ for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) {
+ var path string
+ Switch:
+ switch args[0] {
+ default:
+ i := len(args)
+ for j, c := range args {
+ if unicode.IsSpace(c) {
+ i = j
+ break
+ }
+ }
+ path = args[:i]
+ args = args[i:]
+
+ case '`':
+ i := strings.Index(args[1:], "`")
+ if i < 0 {
+ return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+ }
+ path = args[1 : 1+i]
+ args = args[1+i+1:]
+
+ case '"':
+ i := 1
+ for ; i < len(args); i++ {
+ if args[i] == '\\' {
+ i++
+ continue
+ }
+ if args[i] == '"' {
+ q, err := strconv.Unquote(args[:i+1])
+ if err != nil {
+ return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
+ }
+ path = q
+ args = args[i+1:]
+ break Switch
+ }
+ }
+ if i >= len(args) {
+ return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+ }
+ }
+
+ if args != "" {
+ r, _ := utf8.DecodeRuneInString(args)
+ if !unicode.IsSpace(r) {
+ return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+ }
+ }
+ list = append(list, path)
+ }
+ return list, nil
+}
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
new file mode 100644
index 0000000..da1869e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -0,0 +1,639 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/bio"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+ "crypto/sha256"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "sort"
+ "strconv"
+)
+
+// architecture-independent object file output
+const ArhdrSize = 60
+
+func formathdr(arhdr []byte, name string, size int64) {
+ copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size))
+}
+
+// These modes say which kind of object file to generate.
+// The default use of the toolchain is to set both bits,
+// generating a combined compiler+linker object, one that
+// serves to describe the package to both the compiler and the linker.
+// In fact the compiler and linker read nearly disjoint sections of
+// that file, though, so in a distributed build setting it can be more
+// efficient to split the output into two files, supplying the compiler
+// object only to future compilations and the linker object only to
+// future links.
+//
+// By default a combined object is written, but if -linkobj is specified
+// on the command line then the default -o output is a compiler object
+// and the -linkobj output is a linker object.
+const (
+ modeCompilerObj = 1 << iota
+ modeLinkerObj
+)
+
+func dumpobj() {
+ if linkobj == "" {
+ dumpobj1(outfile, modeCompilerObj|modeLinkerObj)
+ return
+ }
+ dumpobj1(outfile, modeCompilerObj)
+ dumpobj1(linkobj, modeLinkerObj)
+}
+
+func dumpobj1(outfile string, mode int) {
+ bout, err := bio.Create(outfile)
+ if err != nil {
+ flusherrors()
+ fmt.Printf("can't create %s: %v\n", outfile, err)
+ errorexit()
+ }
+ defer bout.Close()
+ bout.WriteString("!<arch>\n")
+
+ if mode&modeCompilerObj != 0 {
+ start := startArchiveEntry(bout)
+ dumpCompilerObj(bout)
+ finishArchiveEntry(bout, start, "__.PKGDEF")
+ }
+ if mode&modeLinkerObj != 0 {
+ start := startArchiveEntry(bout)
+ dumpLinkerObj(bout)
+ finishArchiveEntry(bout, start, "_go_.o")
+ }
+}
+
+func printObjHeader(bout *bio.Writer) {
+ fmt.Fprintf(bout, "go object %s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
+ if buildid != "" {
+ fmt.Fprintf(bout, "build id %q\n", buildid)
+ }
+ if localpkg.Name == "main" {
+ fmt.Fprintf(bout, "main\n")
+ }
+ fmt.Fprintf(bout, "\n") // header ends with blank line
+}
+
+func startArchiveEntry(bout *bio.Writer) int64 {
+ var arhdr [ArhdrSize]byte
+ bout.Write(arhdr[:])
+ return bout.Offset()
+}
+
+func finishArchiveEntry(bout *bio.Writer, start int64, name string) {
+ bout.Flush()
+ size := bout.Offset() - start
+ if size&1 != 0 {
+ bout.WriteByte(0)
+ }
+ bout.MustSeek(start-ArhdrSize, 0)
+
+ var arhdr [ArhdrSize]byte
+ formathdr(arhdr[:], name, size)
+ bout.Write(arhdr[:])
+ bout.Flush()
+ bout.MustSeek(start+size+(size&1), 0)
+}
+
+func dumpCompilerObj(bout *bio.Writer) {
+ printObjHeader(bout)
+ dumpexport(bout)
+}
+
+func dumpdata() {
+ externs := len(externdcl)
+ xtops := len(xtop)
+
+ dumpglobls()
+ addptabs()
+ exportlistLen := len(exportlist)
+ addsignats(externdcl)
+ dumpsignats()
+ dumptabs()
+ ptabsLen := len(ptabs)
+ itabsLen := len(itabs)
+ dumpimportstrings()
+ dumpbasictypes()
+ dumpembeds()
+
+ // Calls to dumpsignats can generate functions,
+ // like method wrappers and hash and equality routines.
+ // Compile any generated functions, process any new resulting types, repeat.
+ // This can't loop forever, because there is no way to generate an infinite
+ // number of types in a finite amount of code.
+ // In the typical case, we loop 0 or 1 times.
+ // It was not until issue 24761 that we found any code that required a loop at all.
+ for {
+ for i := xtops; i < len(xtop); i++ {
+ n := xtop[i]
+ if n.Op == ODCLFUNC {
+ funccompile(n)
+ }
+ }
+ xtops = len(xtop)
+ compileFunctions()
+ dumpsignats()
+ if xtops == len(xtop) {
+ break
+ }
+ }
+
+ // Dump extra globals.
+ tmp := externdcl
+
+ if externdcl != nil {
+ externdcl = externdcl[externs:]
+ }
+ dumpglobls()
+ externdcl = tmp
+
+ if zerosize > 0 {
+ zero := mappkg.Lookup("zero")
+ ggloblsym(zero.Linksym(), int32(zerosize), obj.DUPOK|obj.RODATA)
+ zero.Linksym().Set(obj.AttrStatic, true)
+ }
+
+ addGCLocals()
+
+ if exportlistLen != len(exportlist) {
+ Fatalf("exportlist changed after compile functions loop")
+ }
+ if ptabsLen != len(ptabs) {
+ Fatalf("ptabs changed after compile functions loop")
+ }
+ if itabsLen != len(itabs) {
+ Fatalf("itabs changed after compile functions loop")
+ }
+}
+
+func dumpLinkerObj(bout *bio.Writer) {
+ printObjHeader(bout)
+
+ if len(pragcgobuf) != 0 {
+ // write empty export section; must be before cgo section
+ fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
+ fmt.Fprintf(bout, "\n$$ // cgo\n")
+ if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
+ Fatalf("serializing pragcgobuf: %v", err)
+ }
+ fmt.Fprintf(bout, "\n$$\n\n")
+ }
+
+ fmt.Fprintf(bout, "\n!\n")
+
+ obj.WriteObjFile(Ctxt, bout)
+}
+
+func addptabs() {
+ if !Ctxt.Flag_dynlink || localpkg.Name != "main" {
+ return
+ }
+ for _, exportn := range exportlist {
+ s := exportn.Sym
+ n := asNode(s.Def)
+ if n == nil {
+ continue
+ }
+ if n.Op != ONAME {
+ continue
+ }
+ if !types.IsExported(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: asNode(s.Def).Type})
+ } else {
+ // variable
+ ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(asNode(s.Def).Type)})
+ }
+ }
+}
+
+func dumpGlobal(n *Node) {
+ if n.Type == nil {
+ Fatalf("external %v nil type\n", n)
+ }
+ if n.Class() == PFUNC {
+ return
+ }
+ if n.Sym.Pkg != localpkg {
+ return
+ }
+ dowidth(n.Type)
+ ggloblnod(n)
+}
+
+func dumpGlobalConst(n *Node) {
+ // only export typed constants
+ t := n.Type
+ if t == nil {
+ return
+ }
+ if n.Sym.Pkg != localpkg {
+ return
+ }
+ // only export integer constants for now
+ switch t.Etype {
+ case TINT8:
+ case TINT16:
+ case TINT32:
+ case TINT64:
+ case TINT:
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ case TUINT64:
+ case TUINT:
+ case TUINTPTR:
+ // ok
+ case TIDEAL:
+ if !Isconst(n, CTINT) {
+ return
+ }
+ x := n.Val().U.(*Mpint)
+ if x.Cmp(minintval[TINT]) < 0 || x.Cmp(maxintval[TINT]) > 0 {
+ return
+ }
+ // Ideal integers we export as int (if they fit).
+ t = types.Types[TINT]
+ default:
+ return
+ }
+ Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64Val())
+}
+
+func dumpglobls() {
+ // add globals
+ for _, n := range externdcl {
+ switch n.Op {
+ case ONAME:
+ dumpGlobal(n)
+ case OLITERAL:
+ dumpGlobalConst(n)
+ }
+ }
+
+ sort.Slice(funcsyms, func(i, j int) bool {
+ return funcsyms[i].LinksymName() < funcsyms[j].LinksymName()
+ })
+ for _, s := range funcsyms {
+ sf := s.Pkg.Lookup(funcsymname(s)).Linksym()
+ dsymptr(sf, 0, s.Linksym(), 0)
+ ggloblsym(sf, int32(Widthptr), obj.DUPOK|obj.RODATA)
+ }
+
+ // Do not reprocess funcsyms on next dumpglobls call.
+ funcsyms = nil
+}
+
+// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
+//
+// This is done during the sequential phase after compilation, since
+// global symbols can't be declared during parallel compilation.
+func addGCLocals() {
+ for _, s := range Ctxt.Text {
+ fn := s.Func()
+ if fn == nil {
+ continue
+ }
+ for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals} {
+ if gcsym != nil && !gcsym.OnList() {
+ ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
+ }
+ }
+ if x := fn.StackObjects; x != nil {
+ attr := int16(obj.RODATA)
+ ggloblsym(x, int32(len(x.P)), attr)
+ x.Set(obj.AttrStatic, true)
+ }
+ if x := fn.OpenCodedDeferInfo; x != nil {
+ ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
+ }
+ }
+}
+
+func duintxx(s *obj.LSym, off int, v uint64, wid int) int {
+ if off&(wid-1) != 0 {
+ Fatalf("duintxxLSym: misaligned: v=%d wid=%d off=%d", v, wid, off)
+ }
+ s.WriteInt(Ctxt, int64(off), wid, int64(v))
+ return off + wid
+}
+
+func duint8(s *obj.LSym, off int, v uint8) int {
+ return duintxx(s, off, uint64(v), 1)
+}
+
+func duint16(s *obj.LSym, off int, v uint16) int {
+ return duintxx(s, off, uint64(v), 2)
+}
+
+func duint32(s *obj.LSym, off int, v uint32) int {
+ return duintxx(s, off, uint64(v), 4)
+}
+
+func duintptr(s *obj.LSym, off int, v uint64) int {
+ return duintxx(s, off, v, Widthptr)
+}
+
+func dbvec(s *obj.LSym, off int, bv bvec) int {
+ // Runtime reads the bitmaps as byte arrays. Oblige.
+ for j := 0; int32(j) < bv.n; j += 8 {
+ word := bv.b[j/32]
+ off = duint8(s, off, uint8(word>>(uint(j)%32)))
+ }
+ return off
+}
+
+const (
+ stringSymPrefix = "go.string."
+ stringSymPattern = ".gostring.%d.%x"
+)
+
+// stringsym returns a symbol containing the string s.
+// The symbol contains the string data, not a string header.
+func stringsym(pos src.XPos, s string) (data *obj.LSym) {
+ var symname string
+ if len(s) > 100 {
+ // Huge strings are hashed to avoid long names in object files.
+ // Indulge in some paranoia by writing the length of s, too,
+ // as protection against length extension attacks.
+ // Same pattern is known to fileStringSym below.
+ h := sha256.New()
+ io.WriteString(h, s)
+ symname = fmt.Sprintf(stringSymPattern, len(s), h.Sum(nil))
+ } else {
+ // Small strings get named directly by their contents.
+ symname = strconv.Quote(s)
+ }
+
+ symdata := Ctxt.Lookup(stringSymPrefix + symname)
+ if !symdata.OnList() {
+ off := dstringdata(symdata, 0, s, pos, "string")
+ ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ symdata.Set(obj.AttrContentAddressable, true)
+ }
+
+ return symdata
+}
+
+// fileStringSym returns a symbol for the contents and the size of file.
+// If readonly is true, the symbol shares storage with any literal string
+// or other file with the same content and is placed in a read-only section.
+// If readonly is false, the symbol is a read-write copy separate from any other,
+// for use as the backing store of a []byte.
+// The content hash of file is copied into hash. (If hash is nil, nothing is copied.)
+// The returned symbol contains the data itself, not a string header.
+func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.LSym, int64, error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return nil, 0, err
+ }
+ defer f.Close()
+ info, err := f.Stat()
+ if err != nil {
+ return nil, 0, err
+ }
+ if !info.Mode().IsRegular() {
+ return nil, 0, fmt.Errorf("not a regular file")
+ }
+ size := info.Size()
+ if size <= 1*1024 {
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return nil, 0, err
+ }
+ if int64(len(data)) != size {
+ return nil, 0, fmt.Errorf("file changed between reads")
+ }
+ var sym *obj.LSym
+ if readonly {
+ sym = stringsym(pos, string(data))
+ } else {
+ sym = slicedata(pos, string(data)).Sym.Linksym()
+ }
+ if len(hash) > 0 {
+ sum := sha256.Sum256(data)
+ copy(hash, sum[:])
+ }
+ return sym, size, nil
+ }
+ if size > 2e9 {
+ // ggloblsym takes an int32,
+ // and probably the rest of the toolchain
+ // can't handle such big symbols either.
+ // See golang.org/issue/9862.
+ return nil, 0, fmt.Errorf("file too large")
+ }
+
+ // File is too big to read and keep in memory.
+ // Compute hash if needed for read-only content hashing or if the caller wants it.
+ var sum []byte
+ if readonly || len(hash) > 0 {
+ h := sha256.New()
+ n, err := io.Copy(h, f)
+ if err != nil {
+ return nil, 0, err
+ }
+ if n != size {
+ return nil, 0, fmt.Errorf("file changed between reads")
+ }
+ sum = h.Sum(nil)
+ copy(hash, sum)
+ }
+
+ var symdata *obj.LSym
+ if readonly {
+ symname := fmt.Sprintf(stringSymPattern, size, sum)
+ symdata = Ctxt.Lookup(stringSymPrefix + symname)
+ if !symdata.OnList() {
+ info := symdata.NewFileInfo()
+ info.Name = file
+ info.Size = size
+ ggloblsym(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ // Note: AttrContentAddressable cannot be set here,
+ // because the content-addressable-handling code
+ // does not know about file symbols.
+ }
+ } else {
+ // Emit a zero-length data symbol
+ // and then fix up length and content to use file.
+ symdata = slicedata(pos, "").Sym.Linksym()
+ symdata.Size = size
+ symdata.Type = objabi.SNOPTRDATA
+ info := symdata.NewFileInfo()
+ info.Name = file
+ info.Size = size
+ }
+
+ return symdata, size, nil
+}
+
+var slicedataGen int
+
+func slicedata(pos src.XPos, s string) *Node {
+ slicedataGen++
+ symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
+ sym := localpkg.Lookup(symname)
+ symnode := newname(sym)
+ sym.Def = asTypesNode(symnode)
+
+ lsym := sym.Linksym()
+ off := dstringdata(lsym, 0, s, pos, "slice")
+ ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL)
+
+ return symnode
+}
+
+func slicebytes(nam *Node, s string) {
+ if nam.Op != ONAME {
+ Fatalf("slicebytes %v", nam)
+ }
+ slicesym(nam, slicedata(nam.Pos, s), int64(len(s)))
+}
+
+func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
+ // Objects that are too large will cause the data section to overflow right away,
+ // causing a cryptic error message by the linker. Check for oversize objects here
+ // and provide a useful error message instead.
+ if int64(len(t)) > 2e9 {
+ yyerrorl(pos, "%v with length %v is too big", what, len(t))
+ return 0
+ }
+
+ s.WriteString(Ctxt, int64(off), len(t), t)
+ return off + len(t)
+}
+
+func dsymptr(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
+ off = int(Rnd(int64(off), int64(Widthptr)))
+ s.WriteAddr(Ctxt, int64(off), Widthptr, x, int64(xoff))
+ off += Widthptr
+ return off
+}
+
+func dsymptrOff(s *obj.LSym, off int, x *obj.LSym) int {
+ s.WriteOff(Ctxt, int64(off), x, 0)
+ off += 4
+ return off
+}
+
+func dsymptrWeakOff(s *obj.LSym, off int, x *obj.LSym) int {
+ s.WriteWeakOff(Ctxt, int64(off), x, 0)
+ off += 4
+ return off
+}
+
+// slicesym writes a static slice symbol {&arr, lencap, lencap} to n.
+// arr must be an ONAME. slicesym does not modify n.
+func slicesym(n, arr *Node, lencap int64) {
+ s := n.Sym.Linksym()
+ base := n.Xoffset
+ if arr.Op != ONAME {
+ Fatalf("slicesym non-name arr %v", arr)
+ }
+ s.WriteAddr(Ctxt, base, Widthptr, arr.Sym.Linksym(), arr.Xoffset)
+ s.WriteInt(Ctxt, base+sliceLenOffset, Widthptr, lencap)
+ s.WriteInt(Ctxt, base+sliceCapOffset, Widthptr, lencap)
+}
+
+// addrsym writes the static address of a to n. a must be an ONAME.
+// Neither n nor a is modified.
+func addrsym(n, a *Node) {
+ if n.Op != ONAME {
+ Fatalf("addrsym n op %v", n.Op)
+ }
+ if n.Sym == nil {
+ Fatalf("addrsym nil n sym")
+ }
+ if a.Op != ONAME {
+ Fatalf("addrsym a op %v", a.Op)
+ }
+ s := n.Sym.Linksym()
+ s.WriteAddr(Ctxt, n.Xoffset, Widthptr, a.Sym.Linksym(), a.Xoffset)
+}
+
+// pfuncsym writes the static address of f to n. f must be a global function.
+// Neither n nor f is modified.
+func pfuncsym(n, f *Node) {
+ if n.Op != ONAME {
+ Fatalf("pfuncsym n op %v", n.Op)
+ }
+ if n.Sym == nil {
+ Fatalf("pfuncsym nil n sym")
+ }
+ if f.Class() != PFUNC {
+ Fatalf("pfuncsym class not PFUNC %d", f.Class())
+ }
+ s := n.Sym.Linksym()
+ s.WriteAddr(Ctxt, n.Xoffset, Widthptr, funcsym(f.Sym).Linksym(), f.Xoffset)
+}
+
+// litsym writes the static literal c to n.
+// Neither n nor c is modified.
+func litsym(n, c *Node, wid int) {
+ if n.Op != ONAME {
+ Fatalf("litsym n op %v", n.Op)
+ }
+ if c.Op != OLITERAL {
+ Fatalf("litsym c op %v", c.Op)
+ }
+ if n.Sym == nil {
+ Fatalf("litsym nil n sym")
+ }
+ s := n.Sym.Linksym()
+ switch u := c.Val().U.(type) {
+ case bool:
+ i := int64(obj.Bool2int(u))
+ s.WriteInt(Ctxt, n.Xoffset, wid, i)
+
+ case *Mpint:
+ s.WriteInt(Ctxt, n.Xoffset, wid, u.Int64())
+
+ case *Mpflt:
+ f := u.Float64()
+ switch n.Type.Etype {
+ case TFLOAT32:
+ s.WriteFloat32(Ctxt, n.Xoffset, float32(f))
+ case TFLOAT64:
+ s.WriteFloat64(Ctxt, n.Xoffset, f)
+ }
+
+ case *Mpcplx:
+ r := u.Real.Float64()
+ i := u.Imag.Float64()
+ switch n.Type.Etype {
+ case TCOMPLEX64:
+ s.WriteFloat32(Ctxt, n.Xoffset, float32(r))
+ s.WriteFloat32(Ctxt, n.Xoffset+4, float32(i))
+ case TCOMPLEX128:
+ s.WriteFloat64(Ctxt, n.Xoffset, r)
+ s.WriteFloat64(Ctxt, n.Xoffset+8, i)
+ }
+
+ case string:
+ symdata := stringsym(n.Pos, u)
+ s.WriteAddr(Ctxt, n.Xoffset, Widthptr, symdata, 0)
+ s.WriteInt(Ctxt, n.Xoffset+int64(Widthptr), Widthptr, int64(len(u)))
+
+ default:
+ Fatalf("litsym unhandled OLITERAL %v", c)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/op_string.go b/src/cmd/compile/internal/gc/op_string.go
new file mode 100644
index 0000000..41d5883
--- /dev/null
+++ b/src/cmd/compile/internal/gc/op_string.go
@@ -0,0 +1,175 @@
+// Code generated by "stringer -type=Op -trimprefix=O"; DO NOT EDIT.
+
+package gc
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[OXXX-0]
+ _ = x[ONAME-1]
+ _ = x[ONONAME-2]
+ _ = x[OTYPE-3]
+ _ = x[OPACK-4]
+ _ = x[OLITERAL-5]
+ _ = x[OADD-6]
+ _ = x[OSUB-7]
+ _ = x[OOR-8]
+ _ = x[OXOR-9]
+ _ = x[OADDSTR-10]
+ _ = x[OADDR-11]
+ _ = x[OANDAND-12]
+ _ = x[OAPPEND-13]
+ _ = x[OBYTES2STR-14]
+ _ = x[OBYTES2STRTMP-15]
+ _ = x[ORUNES2STR-16]
+ _ = x[OSTR2BYTES-17]
+ _ = x[OSTR2BYTESTMP-18]
+ _ = x[OSTR2RUNES-19]
+ _ = x[OAS-20]
+ _ = x[OAS2-21]
+ _ = x[OAS2DOTTYPE-22]
+ _ = x[OAS2FUNC-23]
+ _ = x[OAS2MAPR-24]
+ _ = x[OAS2RECV-25]
+ _ = x[OASOP-26]
+ _ = x[OCALL-27]
+ _ = x[OCALLFUNC-28]
+ _ = x[OCALLMETH-29]
+ _ = x[OCALLINTER-30]
+ _ = x[OCALLPART-31]
+ _ = x[OCAP-32]
+ _ = x[OCLOSE-33]
+ _ = x[OCLOSURE-34]
+ _ = x[OCOMPLIT-35]
+ _ = x[OMAPLIT-36]
+ _ = x[OSTRUCTLIT-37]
+ _ = x[OARRAYLIT-38]
+ _ = x[OSLICELIT-39]
+ _ = x[OPTRLIT-40]
+ _ = x[OCONV-41]
+ _ = x[OCONVIFACE-42]
+ _ = x[OCONVNOP-43]
+ _ = x[OCOPY-44]
+ _ = x[ODCL-45]
+ _ = x[ODCLFUNC-46]
+ _ = x[ODCLFIELD-47]
+ _ = x[ODCLCONST-48]
+ _ = x[ODCLTYPE-49]
+ _ = x[ODELETE-50]
+ _ = x[ODOT-51]
+ _ = x[ODOTPTR-52]
+ _ = x[ODOTMETH-53]
+ _ = x[ODOTINTER-54]
+ _ = x[OXDOT-55]
+ _ = x[ODOTTYPE-56]
+ _ = x[ODOTTYPE2-57]
+ _ = x[OEQ-58]
+ _ = x[ONE-59]
+ _ = x[OLT-60]
+ _ = x[OLE-61]
+ _ = x[OGE-62]
+ _ = x[OGT-63]
+ _ = x[ODEREF-64]
+ _ = x[OINDEX-65]
+ _ = x[OINDEXMAP-66]
+ _ = x[OKEY-67]
+ _ = x[OSTRUCTKEY-68]
+ _ = x[OLEN-69]
+ _ = x[OMAKE-70]
+ _ = x[OMAKECHAN-71]
+ _ = x[OMAKEMAP-72]
+ _ = x[OMAKESLICE-73]
+ _ = x[OMAKESLICECOPY-74]
+ _ = x[OMUL-75]
+ _ = x[ODIV-76]
+ _ = x[OMOD-77]
+ _ = x[OLSH-78]
+ _ = x[ORSH-79]
+ _ = x[OAND-80]
+ _ = x[OANDNOT-81]
+ _ = x[ONEW-82]
+ _ = x[ONEWOBJ-83]
+ _ = x[ONOT-84]
+ _ = x[OBITNOT-85]
+ _ = x[OPLUS-86]
+ _ = x[ONEG-87]
+ _ = x[OOROR-88]
+ _ = x[OPANIC-89]
+ _ = x[OPRINT-90]
+ _ = x[OPRINTN-91]
+ _ = x[OPAREN-92]
+ _ = x[OSEND-93]
+ _ = x[OSLICE-94]
+ _ = x[OSLICEARR-95]
+ _ = x[OSLICESTR-96]
+ _ = x[OSLICE3-97]
+ _ = x[OSLICE3ARR-98]
+ _ = x[OSLICEHEADER-99]
+ _ = x[ORECOVER-100]
+ _ = x[ORECV-101]
+ _ = x[ORUNESTR-102]
+ _ = x[OSELRECV-103]
+ _ = x[OSELRECV2-104]
+ _ = x[OIOTA-105]
+ _ = x[OREAL-106]
+ _ = x[OIMAG-107]
+ _ = x[OCOMPLEX-108]
+ _ = x[OALIGNOF-109]
+ _ = x[OOFFSETOF-110]
+ _ = x[OSIZEOF-111]
+ _ = x[OBLOCK-112]
+ _ = x[OBREAK-113]
+ _ = x[OCASE-114]
+ _ = x[OCONTINUE-115]
+ _ = x[ODEFER-116]
+ _ = x[OEMPTY-117]
+ _ = x[OFALL-118]
+ _ = x[OFOR-119]
+ _ = x[OFORUNTIL-120]
+ _ = x[OGOTO-121]
+ _ = x[OIF-122]
+ _ = x[OLABEL-123]
+ _ = x[OGO-124]
+ _ = x[ORANGE-125]
+ _ = x[ORETURN-126]
+ _ = x[OSELECT-127]
+ _ = x[OSWITCH-128]
+ _ = x[OTYPESW-129]
+ _ = x[OTCHAN-130]
+ _ = x[OTMAP-131]
+ _ = x[OTSTRUCT-132]
+ _ = x[OTINTER-133]
+ _ = x[OTFUNC-134]
+ _ = x[OTARRAY-135]
+ _ = x[ODDD-136]
+ _ = x[OINLCALL-137]
+ _ = x[OEFACE-138]
+ _ = x[OITAB-139]
+ _ = x[OIDATA-140]
+ _ = x[OSPTR-141]
+ _ = x[OCLOSUREVAR-142]
+ _ = x[OCFUNC-143]
+ _ = x[OCHECKNIL-144]
+ _ = x[OVARDEF-145]
+ _ = x[OVARKILL-146]
+ _ = x[OVARLIVE-147]
+ _ = x[ORESULT-148]
+ _ = x[OINLMARK-149]
+ _ = x[ORETJMP-150]
+ _ = x[OGETG-151]
+ _ = x[OEND-152]
+}
+
+const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND"
+
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 449, 452, 455, 458, 461, 464, 467, 473, 476, 482, 485, 491, 495, 498, 502, 507, 512, 518, 523, 527, 532, 540, 548, 554, 563, 574, 581, 585, 592, 599, 607, 611, 615, 619, 626, 633, 641, 647, 652, 657, 661, 669, 674, 679, 683, 686, 694, 698, 700, 705, 707, 712, 718, 724, 730, 736, 741, 745, 752, 758, 763, 769, 772, 779, 784, 788, 793, 797, 807, 812, 820, 826, 833, 840, 846, 853, 859, 863, 866}
+
+func (i Op) String() string {
+ if i >= Op(len(_Op_index)-1) {
+ return "Op(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Op_name[_Op_index[i]:_Op_index[i+1]]
+}
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
new file mode 100644
index 0000000..30e1535
--- /dev/null
+++ b/src/cmd/compile/internal/gc/order.go
@@ -0,0 +1,1441 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "fmt"
+)
+
+// Rewrite tree to use separate statements to enforce
+// order of evaluation. Makes walk easier, because it
+// can (after this runs) reorder at will within an expression.
+//
+// Rewrite m[k] op= r into m[k] = m[k] op r if op is / or %.
+//
+// Introduce temporaries as needed by runtime routines.
+// For example, the map runtime routines take the map key
+// by reference, so make sure all map keys are addressable
+// by copying them to temporaries as needed.
+// The same is true for channel operations.
+//
+// Arrange that map index expressions only appear in direct
+// assignments x = m[k] or m[k] = x, never in larger expressions.
+//
+// Arrange that receive expressions only appear in direct assignments
+// x = <-c or as standalone statements <-c, never in larger expressions.
+
+// TODO(rsc): The temporary introduction during multiple assignments
+// should be moved into this file, so that the temporaries can be cleaned
+// and so that conversions implicit in the OAS2FUNC and OAS2RECV
+// nodes can be made explicit and then have their temporaries cleaned.
+
+// TODO(rsc): Goto and multilevel break/continue can jump over
+// inserted VARKILL annotations. Work out a way to handle these.
+// The current implementation is safe, in that it will execute correctly.
+// But it won't reuse temporaries as aggressively as it might, and
+// it can result in unnecessary zeroing of those variables in the function
+// prologue.
+
+// Order holds state during the ordering process.
+type Order struct {
+ out []*Node // list of generated statements
+ temp []*Node // stack of temporary variables
+ free map[string][]*Node // free list of unused temporaries, by type.LongString().
+}
+
+// Order rewrites fn.Nbody to apply the ordering constraints
+// described in the comment at the top of the file.
+func order(fn *Node) {
+ if Debug.W > 1 {
+ s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
+ dumplist(s, fn.Nbody)
+ }
+
+ orderBlock(&fn.Nbody, map[string][]*Node{})
+}
+
+// newTemp allocates a new temporary with the given type,
+// pushes it onto the temp stack, and returns it.
+// If clear is true, newTemp emits code to zero the temporary.
+func (o *Order) newTemp(t *types.Type, clear bool) *Node {
+ var v *Node
+ // Note: LongString is close to the type equality we want,
+ // but not exactly. We still need to double-check with types.Identical.
+ key := t.LongString()
+ a := o.free[key]
+ for i, n := range a {
+ if types.Identical(t, n.Type) {
+ v = a[i]
+ a[i] = a[len(a)-1]
+ a = a[:len(a)-1]
+ o.free[key] = a
+ break
+ }
+ }
+ if v == nil {
+ v = temp(t)
+ }
+ if clear {
+ a := nod(OAS, v, nil)
+ a = typecheck(a, ctxStmt)
+ o.out = append(o.out, a)
+ }
+
+ o.temp = append(o.temp, v)
+ return v
+}
+
+// copyExpr behaves like newTemp but also emits
+// code to initialize the temporary to the value n.
+//
+// The clear argument is provided for use when the evaluation
+// of tmp = n turns into a function call that is passed a pointer
+// to the temporary as the output space. If the call blocks before
+// tmp has been written, the garbage collector will still treat the
+// temporary as live, so we must zero it before entering that call.
+// Today, this only happens for channel receive operations.
+// (The other candidate would be map access, but map access
+// returns a pointer to the result data instead of taking a pointer
+// to be filled in.)
+func (o *Order) copyExpr(n *Node, t *types.Type, clear bool) *Node {
+ v := o.newTemp(t, clear)
+ a := nod(OAS, v, n)
+ a = typecheck(a, ctxStmt)
+ o.out = append(o.out, a)
+ return v
+}
+
+// cheapExpr returns a cheap version of n.
+// The definition of cheap is that n is a variable or constant.
+// If not, cheapExpr allocates a new tmp, emits tmp = n,
+// and then returns tmp.
+func (o *Order) cheapExpr(n *Node) *Node {
+ if n == nil {
+ return nil
+ }
+
+ switch n.Op {
+ case ONAME, OLITERAL:
+ return n
+ case OLEN, OCAP:
+ l := o.cheapExpr(n.Left)
+ if l == n.Left {
+ return n
+ }
+ a := n.sepcopy()
+ a.Left = l
+ return typecheck(a, ctxExpr)
+ }
+
+ return o.copyExpr(n, n.Type, false)
+}
+
+// safeExpr returns a safe version of n.
+// The definition of safe is that n can appear multiple times
+// without violating the semantics of the original program,
+// and that assigning to the safe version has the same effect
+// as assigning to the original n.
+//
+// The intended use is to apply to x when rewriting x += y into x = x + y.
+func (o *Order) safeExpr(n *Node) *Node {
+ switch n.Op {
+ case ONAME, OLITERAL:
+ return n
+
+ case ODOT, OLEN, OCAP:
+ l := o.safeExpr(n.Left)
+ if l == n.Left {
+ return n
+ }
+ a := n.sepcopy()
+ a.Left = l
+ return typecheck(a, ctxExpr)
+
+ case ODOTPTR, ODEREF:
+ l := o.cheapExpr(n.Left)
+ if l == n.Left {
+ return n
+ }
+ a := n.sepcopy()
+ a.Left = l
+ return typecheck(a, ctxExpr)
+
+ case OINDEX, OINDEXMAP:
+ var l *Node
+ if n.Left.Type.IsArray() {
+ l = o.safeExpr(n.Left)
+ } else {
+ l = o.cheapExpr(n.Left)
+ }
+ r := o.cheapExpr(n.Right)
+ if l == n.Left && r == n.Right {
+ return n
+ }
+ a := n.sepcopy()
+ a.Left = l
+ a.Right = r
+ return typecheck(a, ctxExpr)
+
+ default:
+ Fatalf("order.safeExpr %v", n.Op)
+ return nil // not reached
+ }
+}
+
+// isaddrokay reports whether it is okay to pass n's address to runtime routines.
+// Taking the address of a variable makes the liveness and optimization analyses
+// lose track of where the variable's lifetime ends. To avoid hurting the analyses
+// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
+// because we emit explicit VARKILL instructions marking the end of those
+// temporaries' lifetimes.
+func isaddrokay(n *Node) bool {
+ return islvalue(n) && (n.Op != ONAME || n.Class() == PEXTERN || n.IsAutoTmp())
+}
+
+// addrTemp ensures that n is okay to pass by address to runtime routines.
+// If the original argument n is not okay, addrTemp creates a tmp, emits
+// tmp = n, and then returns tmp.
+// The result of addrTemp MUST be assigned back to n, e.g.
+// n.Left = o.addrTemp(n.Left)
+func (o *Order) addrTemp(n *Node) *Node {
+ if consttype(n) != CTxxx {
+ // TODO: expand this to all static composite literal nodes?
+ n = defaultlit(n, nil)
+ dowidth(n.Type)
+ vstat := readonlystaticname(n.Type)
+ var s InitSchedule
+ s.staticassign(vstat, n)
+ if s.out != nil {
+ Fatalf("staticassign of const generated code: %+v", n)
+ }
+ vstat = typecheck(vstat, ctxExpr)
+ return vstat
+ }
+ if isaddrokay(n) {
+ return n
+ }
+ return o.copyExpr(n, n.Type, false)
+}
+
+// mapKeyTemp prepares n to be a key in a map runtime call and returns n.
+// It should only be used for map runtime calls which have *_fast* versions.
+func (o *Order) mapKeyTemp(t *types.Type, n *Node) *Node {
+ // Most map calls need to take the address of the key.
+ // Exception: map*_fast* calls. See golang.org/issue/19015.
+ if mapfast(t) == mapslow {
+ return o.addrTemp(n)
+ }
+ return n
+}
+
+// mapKeyReplaceStrConv replaces OBYTES2STR by OBYTES2STRTMP
+// in n to avoid string allocations for keys in map lookups.
+// Returns a bool that signals if a modification was made.
+//
+// For:
+// x = m[string(k)]
+// x = m[T1{... Tn{..., string(k), ...}]
+// where k is []byte, T1 to Tn is a nesting of struct and array literals,
+// the allocation of backing bytes for the string can be avoided
+// by reusing the []byte backing array. These are special cases
+// for avoiding allocations when converting byte slices to strings.
+// It would be nice to handle these generally, but because
+// []byte keys are not allowed in maps, the use of string(k)
+// comes up in important cases in practice. See issue 3512.
+func mapKeyReplaceStrConv(n *Node) bool {
+ var replaced bool
+ switch n.Op {
+ case OBYTES2STR:
+ n.Op = OBYTES2STRTMP
+ replaced = true
+ case OSTRUCTLIT:
+ for _, elem := range n.List.Slice() {
+ if mapKeyReplaceStrConv(elem.Left) {
+ replaced = true
+ }
+ }
+ case OARRAYLIT:
+ for _, elem := range n.List.Slice() {
+ if elem.Op == OKEY {
+ elem = elem.Right
+ }
+ if mapKeyReplaceStrConv(elem) {
+ replaced = true
+ }
+ }
+ }
+ return replaced
+}
+
+type ordermarker int
+
+// markTemp returns the top of the temporary variable stack.
+func (o *Order) markTemp() ordermarker {
+ return ordermarker(len(o.temp))
+}
+
+// popTemp pops temporaries off the stack until reaching the mark,
+// which must have been returned by markTemp.
+func (o *Order) popTemp(mark ordermarker) {
+ for _, n := range o.temp[mark:] {
+ key := n.Type.LongString()
+ o.free[key] = append(o.free[key], n)
+ }
+ o.temp = o.temp[:mark]
+}
+
+// cleanTempNoPop emits VARKILL instructions to *out
+// for each temporary above the mark on the temporary stack.
+// It does not pop the temporaries from the stack.
+func (o *Order) cleanTempNoPop(mark ordermarker) []*Node {
+ var out []*Node
+ for i := len(o.temp) - 1; i >= int(mark); i-- {
+ n := o.temp[i]
+ kill := nod(OVARKILL, n, nil)
+ kill = typecheck(kill, ctxStmt)
+ out = append(out, kill)
+ }
+ return out
+}
+
+// cleanTemp emits VARKILL instructions for each temporary above the
+// mark on the temporary stack and removes them from the stack.
+func (o *Order) cleanTemp(top ordermarker) {
+ o.out = append(o.out, o.cleanTempNoPop(top)...)
+ o.popTemp(top)
+}
+
+// stmtList orders each of the statements in the list.
+func (o *Order) stmtList(l Nodes) {
+ s := l.Slice()
+ for i := range s {
+ orderMakeSliceCopy(s[i:])
+ o.stmt(s[i])
+ }
+}
+
+// orderMakeSliceCopy matches the pattern:
+// m = OMAKESLICE([]T, x); OCOPY(m, s)
+// and rewrites it to:
+// m = OMAKESLICECOPY([]T, x, s); nil
+func orderMakeSliceCopy(s []*Node) {
+ if Debug.N != 0 || instrumenting {
+ return
+ }
+
+ if len(s) < 2 {
+ return
+ }
+
+ asn := s[0]
+ copyn := s[1]
+
+ if asn == nil || asn.Op != OAS {
+ return
+ }
+ if asn.Left.Op != ONAME {
+ return
+ }
+ if asn.Left.isBlank() {
+ return
+ }
+ maken := asn.Right
+ if maken == nil || maken.Op != OMAKESLICE {
+ return
+ }
+ if maken.Esc == EscNone {
+ return
+ }
+ if maken.Left == nil || maken.Right != nil {
+ return
+ }
+ if copyn.Op != OCOPY {
+ return
+ }
+ if copyn.Left.Op != ONAME {
+ return
+ }
+ if asn.Left.Sym != copyn.Left.Sym {
+ return
+ }
+ if copyn.Right.Op != ONAME {
+ return
+ }
+
+ if copyn.Left.Sym == copyn.Right.Sym {
+ return
+ }
+
+ maken.Op = OMAKESLICECOPY
+ maken.Right = copyn.Right
+ // Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
+ maken.SetBounded(maken.Left.Op == OLEN && samesafeexpr(maken.Left.Left, copyn.Right))
+
+ maken = typecheck(maken, ctxExpr)
+
+ s[1] = nil // remove separate copy call
+
+ return
+}
+
+// edge inserts coverage instrumentation for libfuzzer.
+func (o *Order) edge() {
+ if Debug_libfuzzer == 0 {
+ return
+ }
+
+ // Create a new uint8 counter to be allocated in section
+ // __libfuzzer_extra_counters.
+ counter := staticname(types.Types[TUINT8])
+ counter.Name.SetLibfuzzerExtraCounter(true)
+
+ // counter += 1
+ incr := nod(OASOP, counter, nodintconst(1))
+ incr.SetSubOp(OADD)
+ incr = typecheck(incr, ctxStmt)
+
+ o.out = append(o.out, incr)
+}
+
+// orderBlock orders the block of statements in n into a new slice,
+// and then replaces the old slice in n with the new slice.
+// free is a map that can be used to obtain temporary variables by type.
+func orderBlock(n *Nodes, free map[string][]*Node) {
+ var order Order
+ order.free = free
+ mark := order.markTemp()
+ order.edge()
+ order.stmtList(*n)
+ order.cleanTemp(mark)
+ n.Set(order.out)
+}
+
+// exprInPlace orders the side effects in *np and
+// leaves them as the init list of the final *np.
+// The result of exprInPlace MUST be assigned back to n, e.g.
+// n.Left = o.exprInPlace(n.Left)
+func (o *Order) exprInPlace(n *Node) *Node {
+ var order Order
+ order.free = o.free
+ n = order.expr(n, nil)
+ n = addinit(n, order.out)
+
+ // insert new temporaries from order
+ // at head of outer list.
+ o.temp = append(o.temp, order.temp...)
+ return n
+}
+
+// orderStmtInPlace orders the side effects of the single statement *np
+// and replaces it with the resulting statement list.
+// The result of orderStmtInPlace MUST be assigned back to n, e.g.
+// n.Left = orderStmtInPlace(n.Left)
+// free is a map that can be used to obtain temporary variables by type.
+func orderStmtInPlace(n *Node, free map[string][]*Node) *Node {
+ var order Order
+ order.free = free
+ mark := order.markTemp()
+ order.stmt(n)
+ order.cleanTemp(mark)
+ return liststmt(order.out)
+}
+
+// init moves n's init list to o.out.
+func (o *Order) init(n *Node) {
+ if n.mayBeShared() {
+ // For concurrency safety, don't mutate potentially shared nodes.
+ // First, ensure that no work is required here.
+ if n.Ninit.Len() > 0 {
+ Fatalf("order.init shared node with ninit")
+ }
+ return
+ }
+ o.stmtList(n.Ninit)
+ n.Ninit.Set(nil)
+}
+
+// call orders the call expression n.
+// n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
+func (o *Order) call(n *Node) {
+ if n.Ninit.Len() > 0 {
+ // Caller should have already called o.init(n).
+ Fatalf("%v with unexpected ninit", n.Op)
+ }
+
+ // Builtin functions.
+ if n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER {
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, nil)
+ o.exprList(n.List)
+ return
+ }
+
+ fixVariadicCall(n)
+ n.Left = o.expr(n.Left, nil)
+ o.exprList(n.List)
+
+ if n.Op == OCALLINTER {
+ return
+ }
+ keepAlive := func(arg *Node) {
+ // If the argument is really a pointer being converted to uintptr,
+ // arrange for the pointer to be kept alive until the call returns,
+ // by copying it into a temp and marking that temp
+ // still alive when we pop the temp stack.
+ if arg.Op == OCONVNOP && arg.Left.Type.IsUnsafePtr() {
+ x := o.copyExpr(arg.Left, arg.Left.Type, false)
+ arg.Left = x
+ x.Name.SetAddrtaken(true) // ensure SSA keeps the x variable
+ n.Nbody.Append(typecheck(nod(OVARLIVE, x, nil), ctxStmt))
+ }
+ }
+
+ // Check for "unsafe-uintptr" tag provided by escape analysis.
+ for i, param := range n.Left.Type.Params().FieldSlice() {
+ if param.Note == unsafeUintptrTag || param.Note == uintptrEscapesTag {
+ if arg := n.List.Index(i); arg.Op == OSLICELIT {
+ for _, elt := range arg.List.Slice() {
+ keepAlive(elt)
+ }
+ } else {
+ keepAlive(arg)
+ }
+ }
+ }
+}
+
+// mapAssign appends n to o.out, introducing temporaries
+// to make sure that all map assignments have the form m[k] = x.
+// (Note: expr has already been called on n, so we know k is addressable.)
+//
+// If n is the multiple assignment form ..., m[k], ... = ..., x, ..., the rewrite is
+// t1 = m
+// t2 = k
+// ...., t3, ... = ..., x, ...
+// t1[t2] = t3
+//
+// The temporaries t1, t2 are needed in case the ... being assigned
+// contain m or k. They are usually unnecessary, but in the unnecessary
+// cases they are also typically registerizable, so not much harm done.
+// And this only applies to the multiple-assignment form.
+// We could do a more precise analysis if needed, like in walk.go.
+func (o *Order) mapAssign(n *Node) {
+ switch n.Op {
+ default:
+ Fatalf("order.mapAssign %v", n.Op)
+
+ case OAS, OASOP:
+ if n.Left.Op == OINDEXMAP {
+ // Make sure we evaluate the RHS before starting the map insert.
+ // We need to make sure the RHS won't panic. See issue 22881.
+ if n.Right.Op == OAPPEND {
+ s := n.Right.List.Slice()[1:]
+ for i, n := range s {
+ s[i] = o.cheapExpr(n)
+ }
+ } else {
+ n.Right = o.cheapExpr(n.Right)
+ }
+ }
+ o.out = append(o.out, n)
+
+ case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
+ var post []*Node
+ for i, m := range n.List.Slice() {
+ switch {
+ case m.Op == OINDEXMAP:
+ if !m.Left.IsAutoTmp() {
+ m.Left = o.copyExpr(m.Left, m.Left.Type, false)
+ }
+ if !m.Right.IsAutoTmp() {
+ m.Right = o.copyExpr(m.Right, m.Right.Type, false)
+ }
+ fallthrough
+ case instrumenting && n.Op == OAS2FUNC && !m.isBlank():
+ t := o.newTemp(m.Type, false)
+ n.List.SetIndex(i, t)
+ a := nod(OAS, m, t)
+ a = typecheck(a, ctxStmt)
+ post = append(post, a)
+ }
+ }
+
+ o.out = append(o.out, n)
+ o.out = append(o.out, post...)
+ }
+}
+
+// stmt orders the statement n, appending to o.out.
+// Temporaries created during the statement are cleaned
+// up using VARKILL instructions as possible.
+func (o *Order) stmt(n *Node) {
+ if n == nil {
+ return
+ }
+
+ lno := setlineno(n)
+ o.init(n)
+
+ switch n.Op {
+ default:
+ Fatalf("order.stmt %v", n.Op)
+
+ case OVARKILL, OVARLIVE, OINLMARK:
+ o.out = append(o.out, n)
+
+ case OAS:
+ t := o.markTemp()
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, n.Left)
+ o.mapAssign(n)
+ o.cleanTemp(t)
+
+ case OASOP:
+ t := o.markTemp()
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, nil)
+
+ if instrumenting || n.Left.Op == OINDEXMAP && (n.SubOp() == ODIV || n.SubOp() == OMOD) {
+ // Rewrite m[k] op= r into m[k] = m[k] op r so
+ // that we can ensure that if op panics
+ // because r is zero, the panic happens before
+ // the map assignment.
+
+ n.Left = o.safeExpr(n.Left)
+
+ l := treecopy(n.Left, src.NoXPos)
+ if l.Op == OINDEXMAP {
+ l.SetIndexMapLValue(false)
+ }
+ l = o.copyExpr(l, n.Left.Type, false)
+ n.Right = nod(n.SubOp(), l, n.Right)
+ n.Right = typecheck(n.Right, ctxExpr)
+ n.Right = o.expr(n.Right, nil)
+
+ n.Op = OAS
+ n.ResetAux()
+ }
+
+ o.mapAssign(n)
+ o.cleanTemp(t)
+
+ case OAS2:
+ t := o.markTemp()
+ o.exprList(n.List)
+ o.exprList(n.Rlist)
+ o.mapAssign(n)
+ o.cleanTemp(t)
+
+ // Special: avoid copy of func call n.Right
+ case OAS2FUNC:
+ t := o.markTemp()
+ o.exprList(n.List)
+ o.init(n.Right)
+ o.call(n.Right)
+ o.as2(n)
+ o.cleanTemp(t)
+
+ // Special: use temporary variables to hold result,
+ // so that runtime can take address of temporary.
+ // No temporary for blank assignment.
+ //
+ // OAS2MAPR: make sure key is addressable if needed,
+ // and make sure OINDEXMAP is not copied out.
+ case OAS2DOTTYPE, OAS2RECV, OAS2MAPR:
+ t := o.markTemp()
+ o.exprList(n.List)
+
+ switch r := n.Right; r.Op {
+ case ODOTTYPE2, ORECV:
+ r.Left = o.expr(r.Left, nil)
+ case OINDEXMAP:
+ r.Left = o.expr(r.Left, nil)
+ r.Right = o.expr(r.Right, nil)
+ // See similar conversion for OINDEXMAP below.
+ _ = mapKeyReplaceStrConv(r.Right)
+ r.Right = o.mapKeyTemp(r.Left.Type, r.Right)
+ default:
+ Fatalf("order.stmt: %v", r.Op)
+ }
+
+ o.okAs2(n)
+ o.cleanTemp(t)
+
+ // Special: does not save n onto out.
+ case OBLOCK, OEMPTY:
+ o.stmtList(n.List)
+
+ // Special: n->left is not an expression; save as is.
+ case OBREAK,
+ OCONTINUE,
+ ODCL,
+ ODCLCONST,
+ ODCLTYPE,
+ OFALL,
+ OGOTO,
+ OLABEL,
+ ORETJMP:
+ o.out = append(o.out, n)
+
+ // Special: handle call arguments.
+ case OCALLFUNC, OCALLINTER, OCALLMETH:
+ t := o.markTemp()
+ o.call(n)
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+
+ case OCLOSE,
+ OCOPY,
+ OPRINT,
+ OPRINTN,
+ ORECOVER,
+ ORECV:
+ t := o.markTemp()
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, nil)
+ o.exprList(n.List)
+ o.exprList(n.Rlist)
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+
+ // Special: order arguments to inner call but not call itself.
+ case ODEFER, OGO:
+ t := o.markTemp()
+ o.init(n.Left)
+ o.call(n.Left)
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+
+ case ODELETE:
+ t := o.markTemp()
+ n.List.SetFirst(o.expr(n.List.First(), nil))
+ n.List.SetSecond(o.expr(n.List.Second(), nil))
+ n.List.SetSecond(o.mapKeyTemp(n.List.First().Type, n.List.Second()))
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+
+ // Clean temporaries from condition evaluation at
+ // beginning of loop body and after for statement.
+ case OFOR:
+ t := o.markTemp()
+ n.Left = o.exprInPlace(n.Left)
+ n.Nbody.Prepend(o.cleanTempNoPop(t)...)
+ orderBlock(&n.Nbody, o.free)
+ n.Right = orderStmtInPlace(n.Right, o.free)
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+
+ // Clean temporaries from condition at
+ // beginning of both branches.
+ case OIF:
+ t := o.markTemp()
+ n.Left = o.exprInPlace(n.Left)
+ n.Nbody.Prepend(o.cleanTempNoPop(t)...)
+ n.Rlist.Prepend(o.cleanTempNoPop(t)...)
+ o.popTemp(t)
+ orderBlock(&n.Nbody, o.free)
+ orderBlock(&n.Rlist, o.free)
+ o.out = append(o.out, n)
+
+ // Special: argument will be converted to interface using convT2E
+ // so make sure it is an addressable temporary.
+ case OPANIC:
+ t := o.markTemp()
+ n.Left = o.expr(n.Left, nil)
+ if !n.Left.Type.IsInterface() {
+ n.Left = o.addrTemp(n.Left)
+ }
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+
+ case ORANGE:
+ // n.Right is the expression being ranged over.
+ // order it, and then make a copy if we need one.
+ // We almost always do, to ensure that we don't
+ // see any value changes made during the loop.
+ // Usually the copy is cheap (e.g., array pointer,
+ // chan, slice, string are all tiny).
+ // The exception is ranging over an array value
+ // (not a slice, not a pointer to array),
+ // which must make a copy to avoid seeing updates made during
+ // the range body. Ranging over an array value is uncommon though.
+
+ // Mark []byte(str) range expression to reuse string backing storage.
+ // It is safe because the storage cannot be mutated.
+ if n.Right.Op == OSTR2BYTES {
+ n.Right.Op = OSTR2BYTESTMP
+ }
+
+ t := o.markTemp()
+ n.Right = o.expr(n.Right, nil)
+
+ orderBody := true
+ switch n.Type.Etype {
+ default:
+ Fatalf("order.stmt range %v", n.Type)
+
+ case TARRAY, TSLICE:
+ if n.List.Len() < 2 || n.List.Second().isBlank() {
+ // for i := range x will only use x once, to compute len(x).
+ // No need to copy it.
+ break
+ }
+ fallthrough
+
+ case TCHAN, TSTRING:
+ // chan, string, slice, array ranges use value multiple times.
+ // make copy.
+ r := n.Right
+
+ if r.Type.IsString() && r.Type != types.Types[TSTRING] {
+ r = nod(OCONV, r, nil)
+ r.Type = types.Types[TSTRING]
+ r = typecheck(r, ctxExpr)
+ }
+
+ n.Right = o.copyExpr(r, r.Type, false)
+
+ case TMAP:
+ if isMapClear(n) {
+ // Preserve the body of the map clear pattern so it can
+ // be detected during walk. The loop body will not be used
+ // when optimizing away the range loop to a runtime call.
+ orderBody = false
+ break
+ }
+
+ // copy the map value in case it is a map literal.
+ // TODO(rsc): Make tmp = literal expressions reuse tmp.
+ // For maps tmp is just one word so it hardly matters.
+ r := n.Right
+ n.Right = o.copyExpr(r, r.Type, false)
+
+ // prealloc[n] is the temp for the iterator.
+ // hiter contains pointers and needs to be zeroed.
+ prealloc[n] = o.newTemp(hiter(n.Type), true)
+ }
+ o.exprListInPlace(n.List)
+ if orderBody {
+ orderBlock(&n.Nbody, o.free)
+ }
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+
+ case ORETURN:
+ o.exprList(n.List)
+ o.out = append(o.out, n)
+
+ // Special: clean case temporaries in each block entry.
+ // Select must enter one of its blocks, so there is no
+ // need for a cleaning at the end.
+ // Doubly special: evaluation order for select is stricter
+ // than ordinary expressions. Even something like p.c
+ // has to be hoisted into a temporary, so that it cannot be
+ // reordered after the channel evaluation for a different
+ // case (if p were nil, then the timing of the fault would
+ // give this away).
+ case OSELECT:
+ t := o.markTemp()
+
+ for _, n2 := range n.List.Slice() {
+ if n2.Op != OCASE {
+ Fatalf("order select case %v", n2.Op)
+ }
+ r := n2.Left
+ setlineno(n2)
+
+ // Append any new body prologue to ninit.
+ // The next loop will insert ninit into nbody.
+ if n2.Ninit.Len() != 0 {
+ Fatalf("order select ninit")
+ }
+ if r == nil {
+ continue
+ }
+ switch r.Op {
+ default:
+ Dump("select case", r)
+ Fatalf("unknown op in select %v", r.Op)
+
+ // If this is case x := <-ch or case x, y := <-ch, the case has
+ // the ODCL nodes to declare x and y. We want to delay that
+ // declaration (and possible allocation) until inside the case body.
+ // Delete the ODCL nodes here and recreate them inside the body below.
+ case OSELRECV, OSELRECV2:
+ if r.Colas() {
+ i := 0
+ if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left {
+ i++
+ }
+ if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() {
+ i++
+ }
+ if i >= r.Ninit.Len() {
+ r.Ninit.Set(nil)
+ }
+ }
+
+ if r.Ninit.Len() != 0 {
+ dumplist("ninit", r.Ninit)
+ Fatalf("ninit on select recv")
+ }
+
+ // case x = <-c
+ // case x, ok = <-c
+ // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
+ // r->left == N means 'case <-c'.
+ // c is always evaluated; x and ok are only evaluated when assigned.
+ r.Right.Left = o.expr(r.Right.Left, nil)
+
+ if !r.Right.Left.IsAutoTmp() {
+ r.Right.Left = o.copyExpr(r.Right.Left, r.Right.Left.Type, false)
+ }
+
+ // Introduce temporary for receive and move actual copy into case body.
+ // avoids problems with target being addressed, as usual.
+ // NOTE: If we wanted to be clever, we could arrange for just one
+ // temporary per distinct type, sharing the temp among all receives
+ // with that temp. Similarly one ok bool could be shared among all
+ // the x,ok receives. Not worth doing until there's a clear need.
+ if r.Left != nil && r.Left.isBlank() {
+ r.Left = nil
+ }
+ if r.Left != nil {
+ // use channel element type for temporary to avoid conversions,
+ // such as in case interfacevalue = <-intchan.
+ // the conversion happens in the OAS instead.
+ tmp1 := r.Left
+
+ if r.Colas() {
+ tmp2 := nod(ODCL, tmp1, nil)
+ tmp2 = typecheck(tmp2, ctxStmt)
+ n2.Ninit.Append(tmp2)
+ }
+
+ r.Left = o.newTemp(r.Right.Left.Type.Elem(), r.Right.Left.Type.Elem().HasPointers())
+ tmp2 := nod(OAS, tmp1, r.Left)
+ tmp2 = typecheck(tmp2, ctxStmt)
+ n2.Ninit.Append(tmp2)
+ }
+
+ if r.List.Len() != 0 && r.List.First().isBlank() {
+ r.List.Set(nil)
+ }
+ if r.List.Len() != 0 {
+ tmp1 := r.List.First()
+ if r.Colas() {
+ tmp2 := nod(ODCL, tmp1, nil)
+ tmp2 = typecheck(tmp2, ctxStmt)
+ n2.Ninit.Append(tmp2)
+ }
+
+ r.List.Set1(o.newTemp(types.Types[TBOOL], false))
+ tmp2 := okas(tmp1, r.List.First())
+ tmp2 = typecheck(tmp2, ctxStmt)
+ n2.Ninit.Append(tmp2)
+ }
+ orderBlock(&n2.Ninit, o.free)
+
+ case OSEND:
+ if r.Ninit.Len() != 0 {
+ dumplist("ninit", r.Ninit)
+ Fatalf("ninit on select send")
+ }
+
+ // case c <- x
+ // r->left is c, r->right is x, both are always evaluated.
+ r.Left = o.expr(r.Left, nil)
+
+ if !r.Left.IsAutoTmp() {
+ r.Left = o.copyExpr(r.Left, r.Left.Type, false)
+ }
+ r.Right = o.expr(r.Right, nil)
+ if !r.Right.IsAutoTmp() {
+ r.Right = o.copyExpr(r.Right, r.Right.Type, false)
+ }
+ }
+ }
+ // Now that we have accumulated all the temporaries, clean them.
+ // Also insert any ninit queued during the previous loop.
+ // (The temporary cleaning must follow that ninit work.)
+ for _, n3 := range n.List.Slice() {
+ orderBlock(&n3.Nbody, o.free)
+ n3.Nbody.Prepend(o.cleanTempNoPop(t)...)
+
+ // TODO(mdempsky): Is this actually necessary?
+ // walkselect appears to walk Ninit.
+ n3.Nbody.Prepend(n3.Ninit.Slice()...)
+ n3.Ninit.Set(nil)
+ }
+
+ o.out = append(o.out, n)
+ o.popTemp(t)
+
+ // Special: value being sent is passed as a pointer; make it addressable.
+ case OSEND:
+ t := o.markTemp()
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, nil)
+ if instrumenting {
+ // Force copying to the stack so that (chan T)(nil) <- x
+ // is still instrumented as a read of x.
+ n.Right = o.copyExpr(n.Right, n.Right.Type, false)
+ } else {
+ n.Right = o.addrTemp(n.Right)
+ }
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+
+ // 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 order.stmt on
+ // the if-else chain instead.)
+ // For now just clean all the temporaries at the end.
+ // In practice that's fine.
+ case OSWITCH:
+ if Debug_libfuzzer != 0 && !hasDefaultCase(n) {
+ // Add empty "default:" case for instrumentation.
+ n.List.Append(nod(OCASE, nil, nil))
+ }
+
+ t := o.markTemp()
+ n.Left = o.expr(n.Left, nil)
+ for _, ncas := range n.List.Slice() {
+ if ncas.Op != OCASE {
+ Fatalf("order switch case %v", ncas.Op)
+ }
+ o.exprListInPlace(ncas.List)
+ orderBlock(&ncas.Nbody, o.free)
+ }
+
+ o.out = append(o.out, n)
+ o.cleanTemp(t)
+ }
+
+ lineno = lno
+}
+
+func hasDefaultCase(n *Node) bool {
+ for _, ncas := range n.List.Slice() {
+ if ncas.Op != OCASE {
+ Fatalf("expected case, found %v", ncas.Op)
+ }
+ if ncas.List.Len() == 0 {
+ return true
+ }
+ }
+ return false
+}
+
+// exprList orders the expression list l into o.
+func (o *Order) exprList(l Nodes) {
+ s := l.Slice()
+ for i := range s {
+ s[i] = o.expr(s[i], nil)
+ }
+}
+
+// exprListInPlace orders the expression list l but saves
+// the side effects on the individual expression ninit lists.
+func (o *Order) exprListInPlace(l Nodes) {
+ s := l.Slice()
+ for i := range s {
+ s[i] = o.exprInPlace(s[i])
+ }
+}
+
+// prealloc[x] records the allocation to use for x.
+var prealloc = map[*Node]*Node{}
+
+// expr orders a single expression, appending side
+// effects to o.out as needed.
+// If this is part of an assignment lhs = *np, lhs is given.
+// Otherwise lhs == nil. (When lhs != nil it may be possible
+// to avoid copying the result of the expression to a temporary.)
+// The result of expr MUST be assigned back to n, e.g.
+// n.Left = o.expr(n.Left, lhs)
+func (o *Order) expr(n, lhs *Node) *Node {
+ if n == nil {
+ return n
+ }
+
+ lno := setlineno(n)
+ o.init(n)
+
+ switch n.Op {
+ default:
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, nil)
+ o.exprList(n.List)
+ o.exprList(n.Rlist)
+
+ // 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:
+ o.exprList(n.List)
+
+ if n.List.Len() > 5 {
+ t := types.NewArray(types.Types[TSTRING], int64(n.List.Len()))
+ prealloc[n] = o.newTemp(t, false)
+ }
+
+ // Mark string(byteSlice) arguments to reuse byteSlice backing
+ // buffer during conversion. String concatenation does not
+ // memorize the strings for later use, so it is safe.
+ // However, we can do it only if there is at least one non-empty string literal.
+ // Otherwise if all other arguments are empty strings,
+ // concatstrings will return the reference to the temp string
+ // to the caller.
+ hasbyte := false
+
+ haslit := false
+ for _, n1 := range n.List.Slice() {
+ hasbyte = hasbyte || n1.Op == OBYTES2STR
+ haslit = haslit || n1.Op == OLITERAL && len(n1.StringVal()) != 0
+ }
+
+ if haslit && hasbyte {
+ for _, n2 := range n.List.Slice() {
+ if n2.Op == OBYTES2STR {
+ n2.Op = OBYTES2STRTMP
+ }
+ }
+ }
+
+ case OINDEXMAP:
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, nil)
+ needCopy := false
+
+ if !n.IndexMapLValue() {
+ // Enforce that any []byte slices we are not copying
+ // can not be changed before the map index by forcing
+ // the map index to happen immediately following the
+ // conversions. See copyExpr a few lines below.
+ needCopy = mapKeyReplaceStrConv(n.Right)
+
+ if instrumenting {
+ // Race detector needs the copy so it can
+ // call treecopy on the result.
+ needCopy = true
+ }
+ }
+
+ // key must be addressable
+ n.Right = o.mapKeyTemp(n.Left.Type, n.Right)
+ if needCopy {
+ n = o.copyExpr(n, n.Type, false)
+ }
+
+ // concrete type (not interface) argument might need an addressable
+ // temporary to pass to the runtime conversion routine.
+ case OCONVIFACE:
+ n.Left = o.expr(n.Left, nil)
+ if n.Left.Type.IsInterface() {
+ break
+ }
+ if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || isStaticCompositeLiteral(n.Left) {
+ // Need a temp if we need to pass the address to the conversion function.
+ // We also process static composite literal node here, making a named static global
+ // whose address we can put directly in an interface (see OCONVIFACE case in walk).
+ n.Left = o.addrTemp(n.Left)
+ }
+
+ case OCONVNOP:
+ if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) {
+ // When reordering unsafe.Pointer(f()) into a separate
+ // statement, the conversion and function call must stay
+ // together. See golang.org/issue/15329.
+ o.init(n.Left)
+ o.call(n.Left)
+ if lhs == nil || lhs.Op != ONAME || instrumenting {
+ n = o.copyExpr(n, n.Type, false)
+ }
+ } else {
+ n.Left = o.expr(n.Left, nil)
+ }
+
+ case OANDAND, OOROR:
+ // ... = LHS && RHS
+ //
+ // var r bool
+ // r = LHS
+ // if r { // or !r, for OROR
+ // r = RHS
+ // }
+ // ... = r
+
+ r := o.newTemp(n.Type, false)
+
+ // Evaluate left-hand side.
+ lhs := o.expr(n.Left, nil)
+ o.out = append(o.out, typecheck(nod(OAS, r, lhs), ctxStmt))
+
+ // Evaluate right-hand side, save generated code.
+ saveout := o.out
+ o.out = nil
+ t := o.markTemp()
+ o.edge()
+ rhs := o.expr(n.Right, nil)
+ o.out = append(o.out, typecheck(nod(OAS, r, rhs), ctxStmt))
+ o.cleanTemp(t)
+ gen := o.out
+ o.out = saveout
+
+ // If left-hand side doesn't cause a short-circuit, issue right-hand side.
+ nif := nod(OIF, r, nil)
+ if n.Op == OANDAND {
+ nif.Nbody.Set(gen)
+ } else {
+ nif.Rlist.Set(gen)
+ }
+ o.out = append(o.out, nif)
+ n = r
+
+ case OCALLFUNC,
+ OCALLINTER,
+ OCALLMETH,
+ OCAP,
+ OCOMPLEX,
+ OCOPY,
+ OIMAG,
+ OLEN,
+ OMAKECHAN,
+ OMAKEMAP,
+ OMAKESLICE,
+ OMAKESLICECOPY,
+ ONEW,
+ OREAL,
+ ORECOVER,
+ OSTR2BYTES,
+ OSTR2BYTESTMP,
+ OSTR2RUNES:
+
+ if isRuneCount(n) {
+ // len([]rune(s)) is rewritten to runtime.countrunes(s) later.
+ n.Left.Left = o.expr(n.Left.Left, nil)
+ } else {
+ o.call(n)
+ }
+
+ if lhs == nil || lhs.Op != ONAME || instrumenting {
+ n = o.copyExpr(n, n.Type, false)
+ }
+
+ case OAPPEND:
+ // Check for append(x, make([]T, y)...) .
+ if isAppendOfMake(n) {
+ n.List.SetFirst(o.expr(n.List.First(), nil)) // order x
+ n.List.Second().Left = o.expr(n.List.Second().Left, nil) // order y
+ } else {
+ o.exprList(n.List)
+ }
+
+ if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
+ n = o.copyExpr(n, n.Type, false)
+ }
+
+ case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+ n.Left = o.expr(n.Left, nil)
+ low, high, max := n.SliceBounds()
+ low = o.expr(low, nil)
+ low = o.cheapExpr(low)
+ high = o.expr(high, nil)
+ high = o.cheapExpr(high)
+ max = o.expr(max, nil)
+ max = o.cheapExpr(max)
+ n.SetSliceBounds(low, high, max)
+ if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
+ n = o.copyExpr(n, n.Type, false)
+ }
+
+ case OCLOSURE:
+ if n.Transient() && n.Func.Closure.Func.Cvars.Len() > 0 {
+ prealloc[n] = o.newTemp(closureType(n), false)
+ }
+
+ case OSLICELIT, OCALLPART:
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, nil)
+ o.exprList(n.List)
+ o.exprList(n.Rlist)
+ if n.Transient() {
+ var t *types.Type
+ switch n.Op {
+ case OSLICELIT:
+ t = types.NewArray(n.Type.Elem(), n.Right.Int64Val())
+ case OCALLPART:
+ t = partialCallType(n)
+ }
+ prealloc[n] = o.newTemp(t, false)
+ }
+
+ case ODOTTYPE, ODOTTYPE2:
+ n.Left = o.expr(n.Left, nil)
+ if !isdirectiface(n.Type) || instrumenting {
+ n = o.copyExpr(n, n.Type, true)
+ }
+
+ case ORECV:
+ n.Left = o.expr(n.Left, nil)
+ n = o.copyExpr(n, n.Type, true)
+
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
+ n.Left = o.expr(n.Left, nil)
+ n.Right = o.expr(n.Right, nil)
+
+ t := n.Left.Type
+ switch {
+ case t.IsString():
+ // Mark string(byteSlice) arguments to reuse byteSlice backing
+ // buffer during conversion. String comparison does not
+ // memorize the strings for later use, so it is safe.
+ if n.Left.Op == OBYTES2STR {
+ n.Left.Op = OBYTES2STRTMP
+ }
+ if n.Right.Op == OBYTES2STR {
+ n.Right.Op = OBYTES2STRTMP
+ }
+
+ case t.IsStruct() || t.IsArray():
+ // for complex comparisons, we need both args to be
+ // addressable so we can pass them to the runtime.
+ n.Left = o.addrTemp(n.Left)
+ n.Right = o.addrTemp(n.Right)
+ }
+ case OMAPLIT:
+ // Order map by converting:
+ // map[int]int{
+ // a(): b(),
+ // c(): d(),
+ // e(): f(),
+ // }
+ // to
+ // m := map[int]int{}
+ // m[a()] = b()
+ // m[c()] = d()
+ // m[e()] = f()
+ // Then order the result.
+ // Without this special case, order would otherwise compute all
+ // the keys and values before storing any of them to the map.
+ // See issue 26552.
+ entries := n.List.Slice()
+ statics := entries[:0]
+ var dynamics []*Node
+ for _, r := range entries {
+ if r.Op != OKEY {
+ Fatalf("OMAPLIT entry not OKEY: %v\n", r)
+ }
+
+ if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
+ dynamics = append(dynamics, r)
+ continue
+ }
+
+ // Recursively ordering some static entries can change them to dynamic;
+ // e.g., OCONVIFACE nodes. See #31777.
+ r = o.expr(r, nil)
+ if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
+ dynamics = append(dynamics, r)
+ continue
+ }
+
+ statics = append(statics, r)
+ }
+ n.List.Set(statics)
+
+ if len(dynamics) == 0 {
+ break
+ }
+
+ // Emit the creation of the map (with all its static entries).
+ m := o.newTemp(n.Type, false)
+ as := nod(OAS, m, n)
+ typecheck(as, ctxStmt)
+ o.stmt(as)
+ n = m
+
+ // Emit eval+insert of dynamic entries, one at a time.
+ for _, r := range dynamics {
+ as := nod(OAS, nod(OINDEX, n, r.Left), r.Right)
+ typecheck(as, ctxStmt) // Note: this converts the OINDEX to an OINDEXMAP
+ o.stmt(as)
+ }
+ }
+
+ 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 !ok.isBlank() {
+ val = conv(val, ok.Type)
+ }
+ return nod(OAS, ok, val)
+}
+
+// as2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment.
+// The caller should order the right-hand side of the assignment before calling order.as2.
+// It rewrites,
+// a, b, a = ...
+// as
+// tmp1, tmp2, tmp3 = ...
+// a, b, a = tmp1, tmp2, tmp3
+// This is necessary to ensure left to right assignment order.
+func (o *Order) as2(n *Node) {
+ tmplist := []*Node{}
+ left := []*Node{}
+ for ni, l := range n.List.Slice() {
+ if !l.isBlank() {
+ tmp := o.newTemp(l.Type, l.Type.HasPointers())
+ n.List.SetIndex(ni, tmp)
+ tmplist = append(tmplist, tmp)
+ left = append(left, l)
+ }
+ }
+
+ o.out = append(o.out, n)
+
+ as := nod(OAS2, nil, nil)
+ as.List.Set(left)
+ as.Rlist.Set(tmplist)
+ as = typecheck(as, ctxStmt)
+ o.stmt(as)
+}
+
+// okAs2 orders OAS2XXX with ok.
+// Just like as2, this also adds temporaries to ensure left-to-right assignment.
+func (o *Order) okAs2(n *Node) {
+ var tmp1, tmp2 *Node
+ if !n.List.First().isBlank() {
+ typ := n.Right.Type
+ tmp1 = o.newTemp(typ, typ.HasPointers())
+ }
+
+ if !n.List.Second().isBlank() {
+ tmp2 = o.newTemp(types.Types[TBOOL], false)
+ }
+
+ o.out = append(o.out, n)
+
+ if tmp1 != nil {
+ r := nod(OAS, n.List.First(), tmp1)
+ r = typecheck(r, ctxStmt)
+ o.mapAssign(r)
+ n.List.SetFirst(tmp1)
+ }
+ if tmp2 != nil {
+ r := okas(n.List.Second(), tmp2)
+ r = typecheck(r, ctxStmt)
+ o.mapAssign(r)
+ n.List.SetSecond(tmp2)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
new file mode 100644
index 0000000..353f4b0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -0,0 +1,798 @@
+// Copyright 2011 The Go Authors. 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"
+ "cmd/compile/internal/types"
+ "cmd/internal/dwarf"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+ "cmd/internal/sys"
+ "internal/race"
+ "math/rand"
+ "sort"
+ "sync"
+ "time"
+)
+
+// "Portable" code generation.
+
+var (
+ nBackendWorkers int // number of concurrent backend workers, set by a compiler flag
+ compilequeue []*Node // functions waiting to be compiled
+)
+
+func emitptrargsmap(fn *Node) {
+ if fn.funcname() == "_" || fn.Func.Nname.Sym.Linkname != "" {
+ return
+ }
+ lsym := Ctxt.Lookup(fn.Func.lsym.Name + ".args_stackmap")
+
+ nptr := int(fn.Type.ArgWidth() / int64(Widthptr))
+ bv := bvalloc(int32(nptr) * 2)
+ nbitmap := 1
+ if fn.Type.NumResults() > 0 {
+ nbitmap = 2
+ }
+ off := duint32(lsym, 0, uint32(nbitmap))
+ off = duint32(lsym, off, uint32(bv.n))
+
+ if fn.IsMethod() {
+ onebitwalktype1(fn.Type.Recvs(), 0, bv)
+ }
+ if fn.Type.NumParams() > 0 {
+ onebitwalktype1(fn.Type.Params(), 0, bv)
+ }
+ off = dbvec(lsym, off, bv)
+
+ if fn.Type.NumResults() > 0 {
+ onebitwalktype1(fn.Type.Results(), 0, bv)
+ off = dbvec(lsym, off, bv)
+ }
+
+ ggloblsym(lsym, int32(off), obj.RODATA|obj.LOCAL)
+}
+
+// cmpstackvarlt reports whether the stack variable a sorts before b.
+//
+// Sort the list of stack variables. Autos after anything else,
+// within autos, unused after used, within used, things with
+// pointers first, zeroed things first, and then decreasing size.
+// Because autos are laid out in decreasing addresses
+// on the stack, pointers first, zeroed things first and decreasing size
+// really means, in memory, things with pointers needing zeroing at
+// the top of the stack and increasing in size.
+// Non-autos sort on offset.
+func cmpstackvarlt(a, b *Node) bool {
+ if (a.Class() == PAUTO) != (b.Class() == PAUTO) {
+ return b.Class() == PAUTO
+ }
+
+ if a.Class() != PAUTO {
+ return a.Xoffset < b.Xoffset
+ }
+
+ if a.Name.Used() != b.Name.Used() {
+ return a.Name.Used()
+ }
+
+ ap := a.Type.HasPointers()
+ bp := b.Type.HasPointers()
+ if ap != bp {
+ return ap
+ }
+
+ ap = a.Name.Needzero()
+ bp = b.Name.Needzero()
+ if ap != bp {
+ return ap
+ }
+
+ if a.Type.Width != b.Type.Width {
+ return a.Type.Width > b.Type.Width
+ }
+
+ return a.Sym.Name < b.Sym.Name
+}
+
+// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
+type byStackVar []*Node
+
+func (s byStackVar) Len() int { return len(s) }
+func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
+func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func (s *ssafn) AllocFrame(f *ssa.Func) {
+ s.stksize = 0
+ s.stkptrsize = 0
+ fn := s.curfn.Func
+
+ // Mark the PAUTO's unused.
+ for _, ln := range fn.Dcl {
+ if ln.Class() == PAUTO {
+ ln.Name.SetUsed(false)
+ }
+ }
+
+ for _, l := range f.RegAlloc {
+ if ls, ok := l.(ssa.LocalSlot); ok {
+ ls.N.(*Node).Name.SetUsed(true)
+ }
+ }
+
+ scratchUsed := false
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ if n, ok := v.Aux.(*Node); ok {
+ switch n.Class() {
+ case PPARAM, PPARAMOUT:
+ // Don't modify nodfp; it is a global.
+ if n != nodfp {
+ n.Name.SetUsed(true)
+ }
+ case PAUTO:
+ n.Name.SetUsed(true)
+ }
+ }
+ if !scratchUsed {
+ scratchUsed = v.Op.UsesScratch()
+ }
+
+ }
+ }
+
+ if f.Config.NeedsFpScratch && scratchUsed {
+ s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[TUINT64])
+ }
+
+ sort.Sort(byStackVar(fn.Dcl))
+
+ // Reassign stack offsets of the locals that are used.
+ lastHasPtr := false
+ for i, n := range fn.Dcl {
+ if n.Op != ONAME || n.Class() != PAUTO {
+ continue
+ }
+ if !n.Name.Used() {
+ fn.Dcl = fn.Dcl[:i]
+ break
+ }
+
+ dowidth(n.Type)
+ w := n.Type.Width
+ if w >= thearch.MAXWIDTH || w < 0 {
+ Fatalf("bad width")
+ }
+ if w == 0 && lastHasPtr {
+ // Pad between a pointer-containing object and a zero-sized object.
+ // This prevents a pointer to the zero-sized object from being interpreted
+ // as a pointer to the pointer-containing object (and causing it
+ // to be scanned when it shouldn't be). See issue 24993.
+ w = 1
+ }
+ s.stksize += w
+ s.stksize = Rnd(s.stksize, int64(n.Type.Align))
+ if n.Type.HasPointers() {
+ s.stkptrsize = s.stksize
+ lastHasPtr = true
+ } else {
+ lastHasPtr = false
+ }
+ if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
+ s.stksize = Rnd(s.stksize, int64(Widthptr))
+ }
+ n.Xoffset = -s.stksize
+ }
+
+ s.stksize = Rnd(s.stksize, int64(Widthreg))
+ s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
+}
+
+func funccompile(fn *Node) {
+ if Curfn != nil {
+ Fatalf("funccompile %v inside %v", fn.Func.Nname.Sym, Curfn.Func.Nname.Sym)
+ }
+
+ if fn.Type == nil {
+ if nerrors == 0 {
+ Fatalf("funccompile missing type")
+ }
+ return
+ }
+
+ // assign parameter offsets
+ dowidth(fn.Type)
+
+ if fn.Nbody.Len() == 0 {
+ // Initialize ABI wrappers if necessary.
+ fn.Func.initLSym(false)
+ emitptrargsmap(fn)
+ return
+ }
+
+ dclcontext = PAUTO
+ Curfn = fn
+
+ compile(fn)
+
+ Curfn = nil
+ dclcontext = PEXTERN
+}
+
+func compile(fn *Node) {
+ saveerrors()
+
+ order(fn)
+ if nerrors != 0 {
+ return
+ }
+
+ // Set up the function's LSym early to avoid data races with the assemblers.
+ // Do this before walk, as walk needs the LSym to set attributes/relocations
+ // (e.g. in markTypeUsedInInterface).
+ fn.Func.initLSym(true)
+
+ walk(fn)
+ if nerrors != 0 {
+ return
+ }
+ if instrumenting {
+ instrument(fn)
+ }
+
+ // From this point, there should be no uses of Curfn. Enforce that.
+ Curfn = nil
+
+ if fn.funcname() == "_" {
+ // We don't need to generate code for this function, just report errors in its body.
+ // At this point we've generated any errors needed.
+ // (Beyond here we generate only non-spec errors, like "stack frame too large".)
+ // See issue 29870.
+ return
+ }
+
+ // Make sure type syms are declared for all types that might
+ // be types of stack objects. We need to do this here
+ // because symbols must be allocated before the parallel
+ // phase of the compiler.
+ for _, n := range fn.Func.Dcl {
+ switch n.Class() {
+ case PPARAM, PPARAMOUT, PAUTO:
+ if livenessShouldTrack(n) && n.Name.Addrtaken() {
+ dtypesym(n.Type)
+ // Also make sure we allocate a linker symbol
+ // for the stack object data, for the same reason.
+ if fn.Func.lsym.Func().StackObjects == nil {
+ fn.Func.lsym.Func().StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
+ }
+ }
+ }
+ }
+
+ if compilenow(fn) {
+ compileSSA(fn, 0)
+ } else {
+ compilequeue = append(compilequeue, fn)
+ }
+}
+
+// compilenow reports whether to compile immediately.
+// If functions are not compiled immediately,
+// they are enqueued in compilequeue,
+// which is drained by compileFunctions.
+func compilenow(fn *Node) bool {
+ // Issue 38068: if this function is a method AND an inline
+ // candidate AND was not inlined (yet), put it onto the compile
+ // queue instead of compiling it immediately. This is in case we
+ // wind up inlining it into a method wrapper that is generated by
+ // compiling a function later on in the xtop list.
+ if fn.IsMethod() && isInlinableButNotInlined(fn) {
+ return false
+ }
+ return nBackendWorkers == 1 && Debug_compilelater == 0
+}
+
+// isInlinableButNotInlined returns true if 'fn' was marked as an
+// inline candidate but then never inlined (presumably because we
+// found no call sites).
+func isInlinableButNotInlined(fn *Node) bool {
+ if fn.Func.Nname.Func.Inl == nil {
+ return false
+ }
+ if fn.Sym == nil {
+ return true
+ }
+ return !fn.Sym.Linksym().WasInlined()
+}
+
+const maxStackSize = 1 << 30
+
+// compileSSA builds an SSA backend function,
+// uses it to generate a plist,
+// and flushes that plist to machine code.
+// worker indicates which of the backend workers is doing the processing.
+func compileSSA(fn *Node, worker int) {
+ f := buildssa(fn, worker)
+ // Note: check arg size to fix issue 25507.
+ if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize {
+ largeStackFramesMu.Lock()
+ largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: fn.Type.ArgWidth(), pos: fn.Pos})
+ largeStackFramesMu.Unlock()
+ return
+ }
+ pp := newProgs(fn, worker)
+ defer pp.Free()
+ genssa(f, pp)
+ // Check frame size again.
+ // The check above included only the space needed for local variables.
+ // After genssa, the space needed includes local variables and the callee arg region.
+ // We must do this check prior to calling pp.Flush.
+ // If there are any oversized stack frames,
+ // the assembler may emit inscrutable complaints about invalid instructions.
+ if pp.Text.To.Offset >= maxStackSize {
+ largeStackFramesMu.Lock()
+ locals := f.Frontend().(*ssafn).stksize
+ largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: fn.Type.ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos})
+ largeStackFramesMu.Unlock()
+ return
+ }
+
+ pp.Flush() // assemble, fill in boilerplate, etc.
+ // fieldtrack must be called after pp.Flush. See issue 20014.
+ fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
+}
+
+func init() {
+ if race.Enabled {
+ rand.Seed(time.Now().UnixNano())
+ }
+}
+
+// compileFunctions compiles all functions in compilequeue.
+// It fans out nBackendWorkers to do the work
+// and waits for them to complete.
+func compileFunctions() {
+ if len(compilequeue) != 0 {
+ sizeCalculationDisabled = true // not safe to calculate sizes concurrently
+ if race.Enabled {
+ // Randomize compilation order to try to shake out races.
+ tmp := make([]*Node, len(compilequeue))
+ perm := rand.Perm(len(compilequeue))
+ for i, v := range perm {
+ tmp[v] = compilequeue[i]
+ }
+ copy(compilequeue, tmp)
+ } else {
+ // Compile the longest functions first,
+ // since they're most likely to be the slowest.
+ // This helps avoid stragglers.
+ sort.Slice(compilequeue, func(i, j int) bool {
+ return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len()
+ })
+ }
+ var wg sync.WaitGroup
+ Ctxt.InParallel = true
+ c := make(chan *Node, nBackendWorkers)
+ for i := 0; i < nBackendWorkers; i++ {
+ wg.Add(1)
+ go func(worker int) {
+ for fn := range c {
+ compileSSA(fn, worker)
+ }
+ wg.Done()
+ }(i)
+ }
+ for _, fn := range compilequeue {
+ c <- fn
+ }
+ close(c)
+ compilequeue = nil
+ wg.Wait()
+ Ctxt.InParallel = false
+ sizeCalculationDisabled = false
+ }
+}
+
+func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
+ fn := curfn.(*Node)
+ if fn.Func.Nname != nil {
+ if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
+ Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
+ }
+ }
+
+ var apdecls []*Node
+ // Populate decls for fn.
+ for _, n := range fn.Func.Dcl {
+ if n.Op != ONAME { // might be OTYPE or OLITERAL
+ continue
+ }
+ switch n.Class() {
+ case PAUTO:
+ if !n.Name.Used() {
+ // Text == nil -> generating abstract function
+ if fnsym.Func().Text != nil {
+ Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
+ }
+ continue
+ }
+ case PPARAM, PPARAMOUT:
+ default:
+ continue
+ }
+ apdecls = append(apdecls, n)
+ fnsym.Func().RecordAutoType(ngotype(n).Linksym())
+ }
+
+ decls, dwarfVars := createDwarfVars(fnsym, fn.Func, apdecls)
+
+ // For each type referenced by the functions auto vars but not
+ // already referenced by a dwarf var, attach a dummy relocation to
+ // the function symbol to insure that the type included in DWARF
+ // processing during linking.
+ typesyms := []*obj.LSym{}
+ for t, _ := range fnsym.Func().Autot {
+ typesyms = append(typesyms, t)
+ }
+ sort.Sort(obj.BySymName(typesyms))
+ for _, sym := range typesyms {
+ r := obj.Addrel(infosym)
+ r.Sym = sym
+ r.Type = objabi.R_USETYPE
+ }
+ fnsym.Func().Autot = nil
+
+ var varScopes []ScopeID
+ for _, decl := range decls {
+ pos := declPos(decl)
+ varScopes = append(varScopes, findScope(fn.Func.Marks, pos))
+ }
+
+ scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes)
+ var inlcalls dwarf.InlCalls
+ if genDwarfInline > 0 {
+ inlcalls = assembleInlines(fnsym, dwarfVars)
+ }
+ return scopes, inlcalls
+}
+
+func declPos(decl *Node) src.XPos {
+ if decl.Name.Defn != nil && (decl.Name.Captured() || decl.Name.Byval()) {
+ // It's not clear which position is correct for captured variables here:
+ // * decl.Pos is the wrong position for captured variables, in the inner
+ // function, but it is the right position in the outer function.
+ // * decl.Name.Defn is nil for captured variables that were arguments
+ // on the outer function, however the decl.Pos for those seems to be
+ // correct.
+ // * decl.Name.Defn is the "wrong" thing for variables declared in the
+ // header of a type switch, it's their position in the header, rather
+ // than the position of the case statement. In principle this is the
+ // right thing, but here we prefer the latter because it makes each
+ // instance of the header variable local to the lexical block of its
+ // case statement.
+ // This code is probably wrong for type switch variables that are also
+ // captured.
+ return decl.Name.Defn.Pos
+ }
+ return decl.Pos
+}
+
+// createSimpleVars creates a DWARF entry for every variable declared in the
+// function, claiming that they are permanently on the stack.
+func createSimpleVars(fnsym *obj.LSym, apDecls []*Node) ([]*Node, []*dwarf.Var, map[*Node]bool) {
+ var vars []*dwarf.Var
+ var decls []*Node
+ selected := make(map[*Node]bool)
+ for _, n := range apDecls {
+ if n.IsAutoTmp() {
+ continue
+ }
+
+ decls = append(decls, n)
+ vars = append(vars, createSimpleVar(fnsym, n))
+ selected[n] = true
+ }
+ return decls, vars, selected
+}
+
+func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
+ var abbrev int
+ offs := n.Xoffset
+
+ switch n.Class() {
+ case PAUTO:
+ abbrev = dwarf.DW_ABRV_AUTO
+ if Ctxt.FixedFrameSize() == 0 {
+ offs -= int64(Widthptr)
+ }
+ if objabi.Framepointer_enabled || objabi.GOARCH == "arm64" {
+ // There is a word space for FP on ARM64 even if the frame pointer is disabled
+ offs -= int64(Widthptr)
+ }
+
+ case PPARAM, PPARAMOUT:
+ abbrev = dwarf.DW_ABRV_PARAM
+ offs += Ctxt.FixedFrameSize()
+ default:
+ Fatalf("createSimpleVar unexpected class %v for node %v", n.Class(), n)
+ }
+
+ typename := dwarf.InfoPrefix + typesymname(n.Type)
+ delete(fnsym.Func().Autot, ngotype(n).Linksym())
+ inlIndex := 0
+ if genDwarfInline > 1 {
+ if n.Name.InlFormal() || n.Name.InlLocal() {
+ inlIndex = posInlIndex(n.Pos) + 1
+ if n.Name.InlFormal() {
+ abbrev = dwarf.DW_ABRV_PARAM
+ }
+ }
+ }
+ declpos := Ctxt.InnermostPos(declPos(n))
+ return &dwarf.Var{
+ Name: n.Sym.Name,
+ IsReturnValue: n.Class() == PPARAMOUT,
+ IsInlFormal: n.Name.InlFormal(),
+ Abbrev: abbrev,
+ StackOffset: int32(offs),
+ Type: Ctxt.Lookup(typename),
+ DeclFile: declpos.RelFilename(),
+ DeclLine: declpos.RelLine(),
+ DeclCol: declpos.Col(),
+ InlIndex: int32(inlIndex),
+ ChildIndex: -1,
+ }
+}
+
+// createComplexVars creates recomposed DWARF vars with location lists,
+// suitable for describing optimized code.
+func createComplexVars(fnsym *obj.LSym, fn *Func) ([]*Node, []*dwarf.Var, map[*Node]bool) {
+ debugInfo := fn.DebugInfo
+
+ // Produce a DWARF variable entry for each user variable.
+ var decls []*Node
+ var vars []*dwarf.Var
+ ssaVars := make(map[*Node]bool)
+
+ for varID, dvar := range debugInfo.Vars {
+ n := dvar.(*Node)
+ ssaVars[n] = true
+ for _, slot := range debugInfo.VarSlots[varID] {
+ ssaVars[debugInfo.Slots[slot].N.(*Node)] = true
+ }
+
+ if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID)); dvar != nil {
+ decls = append(decls, n)
+ vars = append(vars, dvar)
+ }
+ }
+
+ return decls, vars, ssaVars
+}
+
+// createDwarfVars process fn, returning a list of DWARF variables and the
+// Nodes they represent.
+func createDwarfVars(fnsym *obj.LSym, fn *Func, apDecls []*Node) ([]*Node, []*dwarf.Var) {
+ // Collect a raw list of DWARF vars.
+ var vars []*dwarf.Var
+ var decls []*Node
+ var selected map[*Node]bool
+ if Ctxt.Flag_locationlists && Ctxt.Flag_optimize && fn.DebugInfo != nil {
+ decls, vars, selected = createComplexVars(fnsym, fn)
+ } else {
+ decls, vars, selected = createSimpleVars(fnsym, apDecls)
+ }
+
+ dcl := apDecls
+ if fnsym.WasInlined() {
+ dcl = preInliningDcls(fnsym)
+ }
+
+ // If optimization is enabled, the list above will typically be
+ // missing some of the original pre-optimization variables in the
+ // function (they may have been promoted to registers, folded into
+ // constants, dead-coded away, etc). Input arguments not eligible
+ // for SSA optimization are also missing. Here we add back in entries
+ // for selected missing vars. Note that the recipe below creates a
+ // conservative location. The idea here is that we want to
+ // communicate to the user that "yes, there is a variable named X
+ // in this function, but no, I don't have enough information to
+ // reliably report its contents."
+ // For non-SSA-able arguments, however, the correct information
+ // is known -- they have a single home on the stack.
+ for _, n := range dcl {
+ if _, found := selected[n]; found {
+ continue
+ }
+ c := n.Sym.Name[0]
+ if c == '.' || n.Type.IsUntyped() {
+ continue
+ }
+ if n.Class() == PPARAM && !canSSAType(n.Type) {
+ // SSA-able args get location lists, and may move in and
+ // out of registers, so those are handled elsewhere.
+ // Autos and named output params seem to get handled
+ // with VARDEF, which creates location lists.
+ // Args not of SSA-able type are treated here; they
+ // are homed on the stack in a single place for the
+ // entire call.
+ vars = append(vars, createSimpleVar(fnsym, n))
+ decls = append(decls, n)
+ continue
+ }
+ typename := dwarf.InfoPrefix + typesymname(n.Type)
+ decls = append(decls, n)
+ abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
+ isReturnValue := (n.Class() == PPARAMOUT)
+ if n.Class() == PPARAM || n.Class() == PPARAMOUT {
+ abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
+ } else if n.Class() == PAUTOHEAP {
+ // If dcl in question has been promoted to heap, do a bit
+ // of extra work to recover original class (auto or param);
+ // see issue 30908. This insures that we get the proper
+ // signature in the abstract function DIE, but leaves a
+ // misleading location for the param (we want pointer-to-heap
+ // and not stack).
+ // TODO(thanm): generate a better location expression
+ stackcopy := n.Name.Param.Stackcopy
+ if stackcopy != nil && (stackcopy.Class() == PPARAM || stackcopy.Class() == PPARAMOUT) {
+ abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
+ isReturnValue = (stackcopy.Class() == PPARAMOUT)
+ }
+ }
+ inlIndex := 0
+ if genDwarfInline > 1 {
+ if n.Name.InlFormal() || n.Name.InlLocal() {
+ inlIndex = posInlIndex(n.Pos) + 1
+ if n.Name.InlFormal() {
+ abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
+ }
+ }
+ }
+ declpos := Ctxt.InnermostPos(n.Pos)
+ vars = append(vars, &dwarf.Var{
+ Name: n.Sym.Name,
+ IsReturnValue: isReturnValue,
+ Abbrev: abbrev,
+ StackOffset: int32(n.Xoffset),
+ Type: Ctxt.Lookup(typename),
+ DeclFile: declpos.RelFilename(),
+ DeclLine: declpos.RelLine(),
+ DeclCol: declpos.Col(),
+ InlIndex: int32(inlIndex),
+ ChildIndex: -1,
+ })
+ // Record go type of to insure that it gets emitted by the linker.
+ fnsym.Func().RecordAutoType(ngotype(n).Linksym())
+ }
+
+ return decls, vars
+}
+
+// Given a function that was inlined at some point during the
+// compilation, return a sorted list of nodes corresponding to the
+// autos/locals in that function prior to inlining. If this is a
+// function that is not local to the package being compiled, then the
+// names of the variables may have been "versioned" to avoid conflicts
+// with local vars; disregard this versioning when sorting.
+func preInliningDcls(fnsym *obj.LSym) []*Node {
+ fn := Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node)
+ var rdcl []*Node
+ for _, n := range fn.Func.Inl.Dcl {
+ c := n.Sym.Name[0]
+ // Avoid reporting "_" parameters, since if there are more than
+ // one, it can result in a collision later on, as in #23179.
+ if unversion(n.Sym.Name) == "_" || c == '.' || n.Type.IsUntyped() {
+ continue
+ }
+ rdcl = append(rdcl, n)
+ }
+ return rdcl
+}
+
+// stackOffset returns the stack location of a LocalSlot relative to the
+// stack pointer, suitable for use in a DWARF location entry. This has nothing
+// to do with its offset in the user variable.
+func stackOffset(slot ssa.LocalSlot) int32 {
+ n := slot.N.(*Node)
+ var base int64
+ switch n.Class() {
+ case PAUTO:
+ if Ctxt.FixedFrameSize() == 0 {
+ base -= int64(Widthptr)
+ }
+ if objabi.Framepointer_enabled || objabi.GOARCH == "arm64" {
+ // There is a word space for FP on ARM64 even if the frame pointer is disabled
+ base -= int64(Widthptr)
+ }
+ case PPARAM, PPARAMOUT:
+ base += Ctxt.FixedFrameSize()
+ }
+ return int32(base + n.Xoffset + slot.Off)
+}
+
+// createComplexVar builds a single DWARF variable entry and location list.
+func createComplexVar(fnsym *obj.LSym, fn *Func, varID ssa.VarID) *dwarf.Var {
+ debug := fn.DebugInfo
+ n := debug.Vars[varID].(*Node)
+
+ var abbrev int
+ switch n.Class() {
+ case PAUTO:
+ abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
+ case PPARAM, PPARAMOUT:
+ abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
+ default:
+ return nil
+ }
+
+ gotype := ngotype(n).Linksym()
+ delete(fnsym.Func().Autot, gotype)
+ typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
+ inlIndex := 0
+ if genDwarfInline > 1 {
+ if n.Name.InlFormal() || n.Name.InlLocal() {
+ inlIndex = posInlIndex(n.Pos) + 1
+ if n.Name.InlFormal() {
+ abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
+ }
+ }
+ }
+ declpos := Ctxt.InnermostPos(n.Pos)
+ dvar := &dwarf.Var{
+ Name: n.Sym.Name,
+ IsReturnValue: n.Class() == PPARAMOUT,
+ IsInlFormal: n.Name.InlFormal(),
+ Abbrev: abbrev,
+ Type: Ctxt.Lookup(typename),
+ // The stack offset is used as a sorting key, so for decomposed
+ // variables just give it the first one. It's not used otherwise.
+ // This won't work well if the first slot hasn't been assigned a stack
+ // location, but it's not obvious how to do better.
+ StackOffset: stackOffset(debug.Slots[debug.VarSlots[varID][0]]),
+ DeclFile: declpos.RelFilename(),
+ DeclLine: declpos.RelLine(),
+ DeclCol: declpos.Col(),
+ InlIndex: int32(inlIndex),
+ ChildIndex: -1,
+ }
+ list := debug.LocationLists[varID]
+ if len(list) != 0 {
+ dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
+ debug.PutLocationList(list, Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
+ }
+ }
+ return dvar
+}
+
+// fieldtrack adds R_USEFIELD relocations to fnsym to record any
+// struct fields that it used.
+func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
+ if fnsym == nil {
+ return
+ }
+ if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
+ return
+ }
+
+ trackSyms := make([]*types.Sym, 0, len(tracked))
+ for sym := range tracked {
+ trackSyms = append(trackSyms, sym)
+ }
+ sort.Sort(symByName(trackSyms))
+ for _, sym := range trackSyms {
+ r := obj.Addrel(fnsym)
+ r.Sym = sym.Linksym()
+ r.Type = objabi.R_USEFIELD
+ }
+}
+
+type symByName []*types.Sym
+
+func (a symByName) Len() int { return len(a) }
+func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
+func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
diff --git a/src/cmd/compile/internal/gc/pgen_test.go b/src/cmd/compile/internal/gc/pgen_test.go
new file mode 100644
index 0000000..b1db298
--- /dev/null
+++ b/src/cmd/compile/internal/gc/pgen_test.go
@@ -0,0 +1,196 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "reflect"
+ "sort"
+ "testing"
+)
+
+func typeWithoutPointers() *types.Type {
+ t := types.New(TSTRUCT)
+ f := &types.Field{Type: types.New(TINT)}
+ t.SetFields([]*types.Field{f})
+ return t
+}
+
+func typeWithPointers() *types.Type {
+ t := types.New(TSTRUCT)
+ f := &types.Field{Type: types.NewPtr(types.New(TINT))}
+ t.SetFields([]*types.Field{f})
+ return t
+}
+
+func markUsed(n *Node) *Node {
+ n.Name.SetUsed(true)
+ return n
+}
+
+func markNeedZero(n *Node) *Node {
+ n.Name.SetNeedzero(true)
+ return n
+}
+
+func nodeWithClass(n Node, c Class) *Node {
+ n.SetClass(c)
+ n.Name = new(Name)
+ return &n
+}
+
+// Test all code paths for cmpstackvarlt.
+func TestCmpstackvar(t *testing.T) {
+ testdata := []struct {
+ a, b *Node
+ lt bool
+ }{
+ {
+ nodeWithClass(Node{}, PAUTO),
+ nodeWithClass(Node{}, PFUNC),
+ false,
+ },
+ {
+ nodeWithClass(Node{}, PFUNC),
+ nodeWithClass(Node{}, PAUTO),
+ true,
+ },
+ {
+ nodeWithClass(Node{Xoffset: 0}, PFUNC),
+ nodeWithClass(Node{Xoffset: 10}, PFUNC),
+ true,
+ },
+ {
+ nodeWithClass(Node{Xoffset: 20}, PFUNC),
+ nodeWithClass(Node{Xoffset: 10}, PFUNC),
+ false,
+ },
+ {
+ nodeWithClass(Node{Xoffset: 10}, PFUNC),
+ nodeWithClass(Node{Xoffset: 10}, PFUNC),
+ false,
+ },
+ {
+ nodeWithClass(Node{Xoffset: 10}, PPARAM),
+ nodeWithClass(Node{Xoffset: 20}, PPARAMOUT),
+ true,
+ },
+ {
+ nodeWithClass(Node{Xoffset: 10}, PPARAMOUT),
+ nodeWithClass(Node{Xoffset: 20}, PPARAM),
+ true,
+ },
+ {
+ markUsed(nodeWithClass(Node{}, PAUTO)),
+ nodeWithClass(Node{}, PAUTO),
+ true,
+ },
+ {
+ nodeWithClass(Node{}, PAUTO),
+ markUsed(nodeWithClass(Node{}, PAUTO)),
+ false,
+ },
+ {
+ nodeWithClass(Node{Type: typeWithoutPointers()}, PAUTO),
+ nodeWithClass(Node{Type: typeWithPointers()}, PAUTO),
+ false,
+ },
+ {
+ nodeWithClass(Node{Type: typeWithPointers()}, PAUTO),
+ nodeWithClass(Node{Type: typeWithoutPointers()}, PAUTO),
+ true,
+ },
+ {
+ markNeedZero(nodeWithClass(Node{Type: &types.Type{}}, PAUTO)),
+ nodeWithClass(Node{Type: &types.Type{}, Name: &Name{}}, PAUTO),
+ true,
+ },
+ {
+ nodeWithClass(Node{Type: &types.Type{}, Name: &Name{}}, PAUTO),
+ markNeedZero(nodeWithClass(Node{Type: &types.Type{}}, PAUTO)),
+ false,
+ },
+ {
+ nodeWithClass(Node{Type: &types.Type{Width: 1}, Name: &Name{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{Width: 2}, Name: &Name{}}, PAUTO),
+ false,
+ },
+ {
+ nodeWithClass(Node{Type: &types.Type{Width: 2}, Name: &Name{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{Width: 1}, Name: &Name{}}, PAUTO),
+ true,
+ },
+ {
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
+ true,
+ },
+ {
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+ false,
+ },
+ {
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+ false,
+ },
+ }
+ for _, d := range testdata {
+ got := cmpstackvarlt(d.a, d.b)
+ if got != d.lt {
+ t.Errorf("want %#v < %#v", d.a, d.b)
+ }
+ // If we expect a < b to be true, check that b < a is false.
+ if d.lt && cmpstackvarlt(d.b, d.a) {
+ t.Errorf("unexpected %#v < %#v", d.b, d.a)
+ }
+ }
+}
+
+func TestStackvarSort(t *testing.T) {
+ inp := []*Node{
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO),
+ nodeWithClass(Node{Xoffset: 0, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+ nodeWithClass(Node{Xoffset: 10, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+ nodeWithClass(Node{Xoffset: 20, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+ markUsed(nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO)),
+ nodeWithClass(Node{Type: typeWithoutPointers(), Sym: &types.Sym{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO),
+ markNeedZero(nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO)),
+ nodeWithClass(Node{Type: &types.Type{Width: 1}, Sym: &types.Sym{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{Width: 2}, Sym: &types.Sym{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
+ }
+ want := []*Node{
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+ nodeWithClass(Node{Xoffset: 0, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+ nodeWithClass(Node{Xoffset: 10, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+ nodeWithClass(Node{Xoffset: 20, Type: &types.Type{}, Sym: &types.Sym{}}, PFUNC),
+ markUsed(nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO)),
+ markNeedZero(nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO)),
+ nodeWithClass(Node{Type: &types.Type{Width: 2}, Sym: &types.Sym{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{Width: 1}, Sym: &types.Sym{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "abc"}}, PAUTO),
+ nodeWithClass(Node{Type: &types.Type{}, Sym: &types.Sym{Name: "xyz"}}, PAUTO),
+ nodeWithClass(Node{Type: typeWithoutPointers(), Sym: &types.Sym{}}, PAUTO),
+ }
+ sort.Sort(byStackVar(inp))
+ if !reflect.DeepEqual(want, inp) {
+ t.Error("sort failed")
+ for i := range inp {
+ g := inp[i]
+ w := want[i]
+ eq := reflect.DeepEqual(w, g)
+ if !eq {
+ t.Log(i, w, g)
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/phi.go b/src/cmd/compile/internal/gc/phi.go
new file mode 100644
index 0000000..5218cd0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/phi.go
@@ -0,0 +1,538 @@
+// Copyright 2016 The Go Authors. 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"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "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.
+// https://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 []*types.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, types.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 *types.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)
+ }
+
+ currentRootLevel := s.level[currentRoot.ID]
+ for _, e := range b.Succs {
+ c := e.Block()
+ // TODO: if the variable is dead at c, skip it.
+ if s.level[c.ID] > currentRootLevel {
+ // a D-edge, or an edge whose target is in currentRoot's subtree.
+ continue
+ }
+ if hasPhi.contains(c.ID) {
+ continue
+ }
+ // Add a phi to block c for variable n.
+ hasPhi.add(c.ID)
+ v := c.NewValue0I(currentRoot.Pos, ssa.OpPhi, typ, int64(n)) // TODO: line number right?
+ // Note: we store the variable number in the phi's AuxInt field. Used temporarily by phi building.
+ s.s.addNamedValue(var_, v)
+ for range c.Preds {
+ 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.
+ }
+ // Only set arguments that have been resolved.
+ // For very wide CFGs, this significantly speeds up phi resolution.
+ // See golang.org/issue/8225.
+ if w := values[v.AuxInt]; w.Op != ssa.OpUnknown {
+ v.SetArg(i, w)
+ }
+ }
+ }
+
+ // 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
+ reachable []bool // which blocks are reachable
+}
+
+func (s *simplePhiState) insertPhis() {
+ s.reachable = ssa.ReachableBlocks(s.f)
+
+ // Find FwdRef ops.
+ for _, b := range s.f.Blocks {
+ for _, v := range b.Values {
+ 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 b == s.f.Entry {
+ // No variable should be live at entry.
+ s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v)
+ }
+ if !s.reachable[b.ID] {
+ // This block is dead.
+ // It doesn't matter what we use here as long as it is well-formed.
+ v.Op = ssa.OpUnknown
+ v.Aux = nil
+ 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.Pos))
+ }
+
+ // 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 *types.Type, var_ *Node, line src.XPos) *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()
+ if !s.reachable[b.ID] {
+ // This is rare; it happens with oddly interleaved infinite loops in dead code.
+ // See issue 19783.
+ break
+ }
+ }
+ // Generate a FwdRef for the variable and return that.
+ v := b.NewValue0A(line, ssa.OpFwdRef, t, var_)
+ 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
new file mode 100644
index 0000000..a48173e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -0,0 +1,1321 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Garbage collector liveness bitmap generation.
+
+// The command line flag -live causes this code to print debug information.
+// The levels are:
+//
+// -live (aka -live=1): print liveness lists as code warnings at safe points
+// -live=2: print an assembly listing with liveness annotations
+//
+// Each level includes the earlier output as well.
+
+package gc
+
+import (
+ "cmd/compile/internal/ssa"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "crypto/md5"
+ "fmt"
+ "strings"
+)
+
+// OpVarDef is an annotation for the liveness analysis, marking a place
+// where a complete initialization (definition) of a variable begins.
+// Since the liveness analysis can see initialization of single-word
+// variables quite easy, OpVarDef is only needed for multi-word
+// variables satisfying isfat(n.Type). For simplicity though, buildssa
+// emits OpVarDef regardless of variable width.
+//
+// An 'OpVarDef x' annotation in the instruction stream tells the liveness
+// analysis to behave as though the variable x is being initialized at that
+// point in the instruction stream. The OpVarDef must appear before the
+// actual (multi-instruction) initialization, and it must also appear after
+// any uses of the previous value, if any. For example, if compiling:
+//
+// x = x[1:]
+//
+// it is important to generate code like:
+//
+// base, len, cap = pieces of x[1:]
+// OpVarDef x
+// x = {base, len, cap}
+//
+// If instead the generated code looked like:
+//
+// OpVarDef x
+// base, len, cap = pieces of x[1:]
+// x = {base, len, cap}
+//
+// then the liveness analysis would decide the previous value of x was
+// unnecessary even though it is about to be used by the x[1:] computation.
+// Similarly, if the generated code looked like:
+//
+// base, len, cap = pieces of x[1:]
+// x = {base, len, cap}
+// OpVarDef x
+//
+// then the liveness analysis will not preserve the new value of x, because
+// the OpVarDef appears to have "overwritten" it.
+//
+// OpVarDef is a bit of a kludge to work around the fact that the instruction
+// stream is working on single-word values but the liveness analysis
+// wants to work on individual variables, which might be multi-word
+// aggregates. It might make sense at some point to look into letting
+// the liveness analysis work on single-word values as well, although
+// there are complications around interface values, slices, and strings,
+// all of which cannot be treated as individual words.
+//
+// OpVarKill is the opposite of OpVarDef: it marks a value as no longer needed,
+// even if its address has been taken. That is, an OpVarKill annotation asserts
+// that its argument is certainly dead, for use when the liveness analysis
+// would not otherwise be able to deduce that fact.
+
+// TODO: get rid of OpVarKill here. It's useful for stack frame allocation
+// so the compiler can allocate two temps to the same location. Here it's now
+// useless, since the implementation of stack objects.
+
+// BlockEffects summarizes the liveness effects on an SSA block.
+type BlockEffects struct {
+ // Computed during Liveness.prologue using only the content of
+ // individual blocks:
+ //
+ // uevar: upward exposed variables (used before set in block)
+ // varkill: killed variables (set in block)
+ uevar bvec
+ varkill bvec
+
+ // Computed during Liveness.solve using control flow information:
+ //
+ // livein: variables live at block entry
+ // liveout: variables live at block exit
+ livein bvec
+ liveout bvec
+}
+
+// A collection of global state used by liveness analysis.
+type Liveness struct {
+ fn *Node
+ f *ssa.Func
+ vars []*Node
+ idx map[*Node]int32
+ stkptrsize int64
+
+ be []BlockEffects
+
+ // allUnsafe indicates that all points in this function are
+ // unsafe-points.
+ allUnsafe bool
+ // unsafePoints bit i is set if Value ID i is an unsafe-point
+ // (preemption is not allowed). Only valid if !allUnsafe.
+ unsafePoints bvec
+
+ // An array with a bit vector for each safe point in the
+ // current Block during Liveness.epilogue. Indexed in Value
+ // order for that block. Additionally, for the entry block
+ // livevars[0] is the entry bitmap. Liveness.compact moves
+ // these to stackMaps.
+ livevars []bvec
+
+ // livenessMap maps from safe points (i.e., CALLs) to their
+ // liveness map indexes.
+ livenessMap LivenessMap
+ stackMapSet bvecSet
+ stackMaps []bvec
+
+ cache progeffectscache
+}
+
+// LivenessMap maps from *ssa.Value to LivenessIndex.
+type LivenessMap struct {
+ vals map[ssa.ID]LivenessIndex
+ // The set of live, pointer-containing variables at the deferreturn
+ // call (only set when open-coded defers are used).
+ deferreturn LivenessIndex
+}
+
+func (m *LivenessMap) reset() {
+ if m.vals == nil {
+ m.vals = make(map[ssa.ID]LivenessIndex)
+ } else {
+ for k := range m.vals {
+ delete(m.vals, k)
+ }
+ }
+ m.deferreturn = LivenessDontCare
+}
+
+func (m *LivenessMap) set(v *ssa.Value, i LivenessIndex) {
+ m.vals[v.ID] = i
+}
+
+func (m LivenessMap) Get(v *ssa.Value) LivenessIndex {
+ // If v isn't in the map, then it's a "don't care" and not an
+ // unsafe-point.
+ if idx, ok := m.vals[v.ID]; ok {
+ return idx
+ }
+ return LivenessIndex{StackMapDontCare, false}
+}
+
+// LivenessIndex stores the liveness map information for a Value.
+type LivenessIndex struct {
+ stackMapIndex int
+
+ // isUnsafePoint indicates that this is an unsafe-point.
+ //
+ // Note that it's possible for a call Value to have a stack
+ // map while also being an unsafe-point. This means it cannot
+ // be preempted at this instruction, but that a preemption or
+ // stack growth may happen in the called function.
+ isUnsafePoint bool
+}
+
+// LivenessDontCare indicates that the liveness information doesn't
+// matter. Currently it is used in deferreturn liveness when we don't
+// actually need it. It should never be emitted to the PCDATA stream.
+var LivenessDontCare = LivenessIndex{StackMapDontCare, true}
+
+// StackMapDontCare indicates that the stack map index at a Value
+// doesn't matter.
+//
+// This is a sentinel value that should never be emitted to the PCDATA
+// stream. We use -1000 because that's obviously never a valid stack
+// index (but -1 is).
+const StackMapDontCare = -1000
+
+func (idx LivenessIndex) StackMapValid() bool {
+ return idx.stackMapIndex != StackMapDontCare
+}
+
+type progeffectscache struct {
+ retuevar []int32
+ tailuevar []int32
+ initialized bool
+}
+
+// livenessShouldTrack reports whether the liveness analysis
+// should track the variable n.
+// We don't care about variables that have no pointers,
+// nor do we care about non-local variables,
+// nor do we care about empty structs (handled by the pointer check),
+// nor do we care about the fake PAUTOHEAP variables.
+func livenessShouldTrack(n *Node) bool {
+ return n.Op == ONAME && (n.Class() == PAUTO || n.Class() == PPARAM || n.Class() == PPARAMOUT) && n.Type.HasPointers()
+}
+
+// getvariables returns the list of on-stack variables that we need to track
+// and a map for looking up indices by *Node.
+func getvariables(fn *Node) ([]*Node, map[*Node]int32) {
+ var vars []*Node
+ for _, n := range fn.Func.Dcl {
+ if livenessShouldTrack(n) {
+ vars = append(vars, n)
+ }
+ }
+ idx := make(map[*Node]int32, len(vars))
+ for i, n := range vars {
+ idx[n] = int32(i)
+ }
+ return vars, idx
+}
+
+func (lv *Liveness) initcache() {
+ if lv.cache.initialized {
+ Fatalf("liveness cache initialized twice")
+ return
+ }
+ lv.cache.initialized = true
+
+ for i, node := range lv.vars {
+ switch node.Class() {
+ case PPARAM:
+ // A return instruction with a p.to is a tail return, which brings
+ // the stack pointer back up (if it ever went down) and then jumps
+ // to a new function entirely. That form of instruction must read
+ // all the parameters for correctness, and similarly it must not
+ // read the out arguments - they won't be set until the new
+ // function runs.
+ lv.cache.tailuevar = append(lv.cache.tailuevar, int32(i))
+
+ case PPARAMOUT:
+ // All results are live at every return point.
+ // Note that this point is after escaping return values
+ // are copied back to the stack using their PAUTOHEAP references.
+ lv.cache.retuevar = append(lv.cache.retuevar, int32(i))
+ }
+ }
+}
+
+// A liveEffect is a set of flags that describe an instruction's
+// liveness effects on a variable.
+//
+// The possible flags are:
+// uevar - used by the instruction
+// varkill - killed by the instruction (set)
+// A kill happens after the use (for an instruction that updates a value, for example).
+type liveEffect int
+
+const (
+ uevar liveEffect = 1 << iota
+ varkill
+)
+
+// valueEffects returns the index of a variable in lv.vars and the
+// liveness effects v has on that variable.
+// If v does not affect any tracked variables, it returns -1, 0.
+func (lv *Liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
+ n, e := affectedNode(v)
+ if e == 0 || n == nil || n.Op != ONAME { // cheapest checks first
+ return -1, 0
+ }
+
+ // AllocFrame has dropped unused variables from
+ // lv.fn.Func.Dcl, but they might still be referenced by
+ // OpVarFoo pseudo-ops. Ignore them to prevent "lost track of
+ // variable" ICEs (issue 19632).
+ switch v.Op {
+ case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
+ if !n.Name.Used() {
+ return -1, 0
+ }
+ }
+
+ var effect liveEffect
+ // Read is a read, obviously.
+ //
+ // Addr is a read also, as any subsequent holder of the pointer must be able
+ // to see all the values (including initialization) written so far.
+ // This also prevents a variable from "coming back from the dead" and presenting
+ // stale pointers to the garbage collector. See issue 28445.
+ if e&(ssa.SymRead|ssa.SymAddr) != 0 {
+ effect |= uevar
+ }
+ if e&ssa.SymWrite != 0 && (!isfat(n.Type) || v.Op == ssa.OpVarDef) {
+ effect |= varkill
+ }
+
+ if effect == 0 {
+ return -1, 0
+ }
+
+ if pos, ok := lv.idx[n]; ok {
+ return pos, effect
+ }
+ return -1, 0
+}
+
+// affectedNode returns the *Node affected by v
+func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
+ // Special cases.
+ switch v.Op {
+ case ssa.OpLoadReg:
+ n, _ := AutoVar(v.Args[0])
+ return n, ssa.SymRead
+ case ssa.OpStoreReg:
+ n, _ := AutoVar(v)
+ return n, ssa.SymWrite
+
+ case ssa.OpVarLive:
+ return v.Aux.(*Node), ssa.SymRead
+ case ssa.OpVarDef, ssa.OpVarKill:
+ return v.Aux.(*Node), ssa.SymWrite
+ case ssa.OpKeepAlive:
+ n, _ := AutoVar(v.Args[0])
+ return n, ssa.SymRead
+ }
+
+ e := v.Op.SymEffect()
+ if e == 0 {
+ return nil, 0
+ }
+
+ switch a := v.Aux.(type) {
+ case nil, *obj.LSym:
+ // ok, but no node
+ return nil, e
+ case *Node:
+ return a, e
+ default:
+ Fatalf("weird aux: %s", v.LongString())
+ return nil, e
+ }
+}
+
+type livenessFuncCache struct {
+ be []BlockEffects
+ livenessMap LivenessMap
+}
+
+// Constructs a new liveness structure used to hold the global state of the
+// liveness computation. The cfg argument is a slice of *BasicBlocks and the
+// vars argument is a slice of *Nodes.
+func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkptrsize int64) *Liveness {
+ lv := &Liveness{
+ fn: fn,
+ f: f,
+ vars: vars,
+ idx: idx,
+ stkptrsize: stkptrsize,
+ }
+
+ // Significant sources of allocation are kept in the ssa.Cache
+ // and reused. Surprisingly, the bit vectors themselves aren't
+ // a major source of allocation, but the liveness maps are.
+ if lc, _ := f.Cache.Liveness.(*livenessFuncCache); lc == nil {
+ // Prep the cache so liveness can fill it later.
+ f.Cache.Liveness = new(livenessFuncCache)
+ } else {
+ if cap(lc.be) >= f.NumBlocks() {
+ lv.be = lc.be[:f.NumBlocks()]
+ }
+ lv.livenessMap = LivenessMap{vals: lc.livenessMap.vals, deferreturn: LivenessDontCare}
+ lc.livenessMap.vals = nil
+ }
+ if lv.be == nil {
+ lv.be = make([]BlockEffects, f.NumBlocks())
+ }
+
+ nblocks := int32(len(f.Blocks))
+ nvars := int32(len(vars))
+ bulk := bvbulkalloc(nvars, nblocks*7)
+ for _, b := range f.Blocks {
+ be := lv.blockEffects(b)
+
+ be.uevar = bulk.next()
+ be.varkill = bulk.next()
+ be.livein = bulk.next()
+ be.liveout = bulk.next()
+ }
+ lv.livenessMap.reset()
+
+ lv.markUnsafePoints()
+ return lv
+}
+
+func (lv *Liveness) blockEffects(b *ssa.Block) *BlockEffects {
+ return &lv.be[b.ID]
+}
+
+// NOTE: The bitmap for a specific type t could be cached in t after
+// the first run and then simply copied into bv at the correct offset
+// on future calls with the same type t.
+func onebitwalktype1(t *types.Type, off int64, bv bvec) {
+ if t.Align > 0 && off&int64(t.Align-1) != 0 {
+ Fatalf("onebitwalktype1: invalid initial alignment: type %v has alignment %d, but offset is %v", t, t.Align, off)
+ }
+ if !t.HasPointers() {
+ // Note: this case ensures that pointers to go:notinheap types
+ // are not considered pointers by garbage collection and stack copying.
+ return
+ }
+
+ switch t.Etype {
+ case TPTR, TUNSAFEPTR, TFUNC, TCHAN, TMAP:
+ if off&int64(Widthptr-1) != 0 {
+ Fatalf("onebitwalktype1: invalid alignment, %v", t)
+ }
+ bv.Set(int32(off / int64(Widthptr))) // pointer
+
+ case TSTRING:
+ // struct { byte *str; intgo len; }
+ if off&int64(Widthptr-1) != 0 {
+ Fatalf("onebitwalktype1: invalid alignment, %v", t)
+ }
+ bv.Set(int32(off / int64(Widthptr))) //pointer in first slot
+
+ case TINTER:
+ // struct { Itab *tab; void *data; }
+ // or, when isnilinter(t)==true:
+ // struct { Type *type; void *data; }
+ if off&int64(Widthptr-1) != 0 {
+ Fatalf("onebitwalktype1: invalid alignment, %v", t)
+ }
+ // The first word of an interface is a pointer, but we don't
+ // treat it as such.
+ // 1. If it is a non-empty interface, the pointer points to an itab
+ // which is always in persistentalloc space.
+ // 2. If it is an empty interface, the pointer points to a _type.
+ // a. If it is a compile-time-allocated type, it points into
+ // the read-only data section.
+ // b. If it is a reflect-allocated type, it points into the Go heap.
+ // Reflect is responsible for keeping a reference to
+ // the underlying type so it won't be GCd.
+ // If we ever have a moving GC, we need to change this for 2b (as
+ // well as scan itabs to update their itab._type fields).
+ bv.Set(int32(off/int64(Widthptr) + 1)) // pointer in second slot
+
+ case TSLICE:
+ // struct { byte *array; uintgo len; uintgo cap; }
+ if off&int64(Widthptr-1) != 0 {
+ Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
+ }
+ bv.Set(int32(off / int64(Widthptr))) // pointer in first slot (BitsPointer)
+
+ case TARRAY:
+ elt := t.Elem()
+ if elt.Width == 0 {
+ // Short-circuit for #20739.
+ break
+ }
+ for i := int64(0); i < t.NumElem(); i++ {
+ onebitwalktype1(elt, off, bv)
+ off += elt.Width
+ }
+
+ case TSTRUCT:
+ for _, f := range t.Fields().Slice() {
+ onebitwalktype1(f.Type, off+f.Offset, bv)
+ }
+
+ default:
+ Fatalf("onebitwalktype1: unexpected type, %v", t)
+ }
+}
+
+// Generates live pointer value maps for arguments and local variables. The
+// this argument and the in arguments are always assumed live. The vars
+// argument is a slice of *Nodes.
+func (lv *Liveness) pointerMap(liveout bvec, vars []*Node, args, locals bvec) {
+ for i := int32(0); ; i++ {
+ i = liveout.Next(i)
+ if i < 0 {
+ break
+ }
+ node := vars[i]
+ switch node.Class() {
+ case PAUTO:
+ onebitwalktype1(node.Type, node.Xoffset+lv.stkptrsize, locals)
+
+ case PPARAM, PPARAMOUT:
+ onebitwalktype1(node.Type, node.Xoffset, args)
+ }
+ }
+}
+
+// allUnsafe indicates that all points in this function are
+// unsafe-points.
+func allUnsafe(f *ssa.Func) bool {
+ // The runtime assumes the only safe-points are function
+ // prologues (because that's how it used to be). We could and
+ // should improve that, but for now keep consider all points
+ // in the runtime unsafe. obj will add prologues and their
+ // safe-points.
+ //
+ // go:nosplit functions are similar. Since safe points used to
+ // be coupled with stack checks, go:nosplit often actually
+ // means "no safe points in this function".
+ return compiling_runtime || f.NoSplit
+}
+
+// markUnsafePoints finds unsafe points and computes lv.unsafePoints.
+func (lv *Liveness) markUnsafePoints() {
+ if allUnsafe(lv.f) {
+ // No complex analysis necessary.
+ lv.allUnsafe = true
+ return
+ }
+
+ lv.unsafePoints = bvalloc(int32(lv.f.NumValues()))
+
+ // Mark architecture-specific unsafe points.
+ for _, b := range lv.f.Blocks {
+ for _, v := range b.Values {
+ if v.Op.UnsafePoint() {
+ lv.unsafePoints.Set(int32(v.ID))
+ }
+ }
+ }
+
+ // Mark write barrier unsafe points.
+ for _, wbBlock := range lv.f.WBLoads {
+ if wbBlock.Kind == ssa.BlockPlain && len(wbBlock.Values) == 0 {
+ // The write barrier block was optimized away
+ // but we haven't done dead block elimination.
+ // (This can happen in -N mode.)
+ continue
+ }
+ // Check that we have the expected diamond shape.
+ if len(wbBlock.Succs) != 2 {
+ lv.f.Fatalf("expected branch at write barrier block %v", wbBlock)
+ }
+ s0, s1 := wbBlock.Succs[0].Block(), wbBlock.Succs[1].Block()
+ if s0 == s1 {
+ // There's no difference between write barrier on and off.
+ // Thus there's no unsafe locations. See issue 26024.
+ continue
+ }
+ if s0.Kind != ssa.BlockPlain || s1.Kind != ssa.BlockPlain {
+ lv.f.Fatalf("expected successors of write barrier block %v to be plain", wbBlock)
+ }
+ if s0.Succs[0].Block() != s1.Succs[0].Block() {
+ lv.f.Fatalf("expected successors of write barrier block %v to converge", wbBlock)
+ }
+
+ // Flow backwards from the control value to find the
+ // flag load. We don't know what lowered ops we're
+ // looking for, but all current arches produce a
+ // single op that does the memory load from the flag
+ // address, so we look for that.
+ var load *ssa.Value
+ v := wbBlock.Controls[0]
+ for {
+ if sym, ok := v.Aux.(*obj.LSym); ok && sym == writeBarrier {
+ load = v
+ break
+ }
+ switch v.Op {
+ case ssa.Op386TESTL:
+ // 386 lowers Neq32 to (TESTL cond cond),
+ if v.Args[0] == v.Args[1] {
+ v = v.Args[0]
+ continue
+ }
+ case ssa.Op386MOVLload, ssa.OpARM64MOVWUload, ssa.OpPPC64MOVWZload, ssa.OpWasmI64Load32U:
+ // Args[0] is the address of the write
+ // barrier control. Ignore Args[1],
+ // which is the mem operand.
+ // TODO: Just ignore mem operands?
+ v = v.Args[0]
+ continue
+ }
+ // Common case: just flow backwards.
+ if len(v.Args) != 1 {
+ v.Fatalf("write barrier control value has more than one argument: %s", v.LongString())
+ }
+ v = v.Args[0]
+ }
+
+ // Mark everything after the load unsafe.
+ found := false
+ for _, v := range wbBlock.Values {
+ found = found || v == load
+ if found {
+ lv.unsafePoints.Set(int32(v.ID))
+ }
+ }
+
+ // Mark the two successor blocks unsafe. These come
+ // back together immediately after the direct write in
+ // one successor and the last write barrier call in
+ // the other, so there's no need to be more precise.
+ for _, succ := range wbBlock.Succs {
+ for _, v := range succ.Block().Values {
+ lv.unsafePoints.Set(int32(v.ID))
+ }
+ }
+ }
+
+ // Find uintptr -> unsafe.Pointer conversions and flood
+ // unsafeness back to a call (which is always a safe point).
+ //
+ // Looking for the uintptr -> unsafe.Pointer conversion has a
+ // few advantages over looking for unsafe.Pointer -> uintptr
+ // conversions:
+ //
+ // 1. We avoid needlessly blocking safe-points for
+ // unsafe.Pointer -> uintptr conversions that never go back to
+ // a Pointer.
+ //
+ // 2. We don't have to detect calls to reflect.Value.Pointer,
+ // reflect.Value.UnsafeAddr, and reflect.Value.InterfaceData,
+ // which are implicit unsafe.Pointer -> uintptr conversions.
+ // We can't even reliably detect this if there's an indirect
+ // call to one of these methods.
+ //
+ // TODO: For trivial unsafe.Pointer arithmetic, it would be
+ // nice to only flood as far as the unsafe.Pointer -> uintptr
+ // conversion, but it's hard to know which argument of an Add
+ // or Sub to follow.
+ var flooded bvec
+ var flood func(b *ssa.Block, vi int)
+ flood = func(b *ssa.Block, vi int) {
+ if flooded.n == 0 {
+ flooded = bvalloc(int32(lv.f.NumBlocks()))
+ }
+ if flooded.Get(int32(b.ID)) {
+ return
+ }
+ for i := vi - 1; i >= 0; i-- {
+ v := b.Values[i]
+ if v.Op.IsCall() {
+ // Uintptrs must not contain live
+ // pointers across calls, so stop
+ // flooding.
+ return
+ }
+ lv.unsafePoints.Set(int32(v.ID))
+ }
+ if vi == len(b.Values) {
+ // We marked all values in this block, so no
+ // need to flood this block again.
+ flooded.Set(int32(b.ID))
+ }
+ for _, pred := range b.Preds {
+ flood(pred.Block(), len(pred.Block().Values))
+ }
+ }
+ for _, b := range lv.f.Blocks {
+ for i, v := range b.Values {
+ if !(v.Op == ssa.OpConvert && v.Type.IsPtrShaped()) {
+ continue
+ }
+ // Flood the unsafe-ness of this backwards
+ // until we hit a call.
+ flood(b, i+1)
+ }
+ }
+}
+
+// Returns true for instructions that must have a stack map.
+//
+// This does not necessarily mean the instruction is a safe-point. In
+// particular, call Values can have a stack map in case the callee
+// grows the stack, but not themselves be a safe-point.
+func (lv *Liveness) hasStackMap(v *ssa.Value) bool {
+ if !v.Op.IsCall() {
+ return false
+ }
+ // typedmemclr and typedmemmove are write barriers and
+ // deeply non-preemptible. They are unsafe points and
+ // hence should not have liveness maps.
+ if sym, ok := v.Aux.(*ssa.AuxCall); ok && (sym.Fn == typedmemclr || sym.Fn == typedmemmove) {
+ return false
+ }
+ return true
+}
+
+// Initializes the sets for solving the live variables. Visits all the
+// instructions in each basic block to summarizes the information at each basic
+// block
+func (lv *Liveness) prologue() {
+ lv.initcache()
+
+ for _, b := range lv.f.Blocks {
+ be := lv.blockEffects(b)
+
+ // Walk the block instructions backward and update the block
+ // effects with the each prog effects.
+ for j := len(b.Values) - 1; j >= 0; j-- {
+ pos, e := lv.valueEffects(b.Values[j])
+ if e&varkill != 0 {
+ be.varkill.Set(pos)
+ be.uevar.Unset(pos)
+ }
+ if e&uevar != 0 {
+ be.uevar.Set(pos)
+ }
+ }
+ }
+}
+
+// Solve the liveness dataflow equations.
+func (lv *Liveness) solve() {
+ // These temporary bitvectors exist to avoid successive allocations and
+ // frees within the loop.
+ nvars := int32(len(lv.vars))
+ newlivein := bvalloc(nvars)
+ newliveout := bvalloc(nvars)
+
+ // Walk blocks in postorder ordering. This improves convergence.
+ po := lv.f.Postorder()
+
+ // Iterate through the blocks in reverse round-robin fashion. A work
+ // queue might be slightly faster. As is, the number of iterations is
+ // so low that it hardly seems to be worth the complexity.
+
+ for change := true; change; {
+ change = false
+ for _, b := range po {
+ be := lv.blockEffects(b)
+
+ newliveout.Clear()
+ switch b.Kind {
+ case ssa.BlockRet:
+ for _, pos := range lv.cache.retuevar {
+ newliveout.Set(pos)
+ }
+ case ssa.BlockRetJmp:
+ for _, pos := range lv.cache.tailuevar {
+ newliveout.Set(pos)
+ }
+ case ssa.BlockExit:
+ // panic exit - nothing to do
+ default:
+ // A variable is live on output from this block
+ // if it is live on input to some successor.
+ //
+ // out[b] = \bigcup_{s \in succ[b]} in[s]
+ newliveout.Copy(lv.blockEffects(b.Succs[0].Block()).livein)
+ for _, succ := range b.Succs[1:] {
+ newliveout.Or(newliveout, lv.blockEffects(succ.Block()).livein)
+ }
+ }
+
+ if !be.liveout.Eq(newliveout) {
+ change = true
+ be.liveout.Copy(newliveout)
+ }
+
+ // A variable is live on input to this block
+ // if it is used by this block, or live on output from this block and
+ // not set by the code in this block.
+ //
+ // in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
+ newlivein.AndNot(be.liveout, be.varkill)
+ be.livein.Or(newlivein, be.uevar)
+ }
+ }
+}
+
+// Visits all instructions in a basic block and computes a bit vector of live
+// variables at each safe point locations.
+func (lv *Liveness) epilogue() {
+ nvars := int32(len(lv.vars))
+ liveout := bvalloc(nvars)
+ livedefer := bvalloc(nvars) // always-live variables
+
+ // If there is a defer (that could recover), then all output
+ // parameters are live all the time. In addition, any locals
+ // that are pointers to heap-allocated output parameters are
+ // also always live (post-deferreturn code needs these
+ // pointers to copy values back to the stack).
+ // TODO: if the output parameter is heap-allocated, then we
+ // don't need to keep the stack copy live?
+ if lv.fn.Func.HasDefer() {
+ for i, n := range lv.vars {
+ if n.Class() == PPARAMOUT {
+ if n.Name.IsOutputParamHeapAddr() {
+ // Just to be paranoid. Heap addresses are PAUTOs.
+ Fatalf("variable %v both output param and heap output param", n)
+ }
+ if n.Name.Param.Heapaddr != nil {
+ // If this variable moved to the heap, then
+ // its stack copy is not live.
+ continue
+ }
+ // Note: zeroing is handled by zeroResults in walk.go.
+ livedefer.Set(int32(i))
+ }
+ if n.Name.IsOutputParamHeapAddr() {
+ // This variable will be overwritten early in the function
+ // prologue (from the result of a mallocgc) but we need to
+ // zero it in case that malloc causes a stack scan.
+ n.Name.SetNeedzero(true)
+ livedefer.Set(int32(i))
+ }
+ if n.Name.OpenDeferSlot() {
+ // Open-coded defer args slots must be live
+ // everywhere in a function, since a panic can
+ // occur (almost) anywhere. Because it is live
+ // everywhere, it must be zeroed on entry.
+ livedefer.Set(int32(i))
+ // It was already marked as Needzero when created.
+ if !n.Name.Needzero() {
+ Fatalf("all pointer-containing defer arg slots should have Needzero set")
+ }
+ }
+ }
+ }
+
+ // We must analyze the entry block first. The runtime assumes
+ // the function entry map is index 0. Conveniently, layout
+ // already ensured that the entry block is first.
+ if lv.f.Entry != lv.f.Blocks[0] {
+ lv.f.Fatalf("entry block must be first")
+ }
+
+ {
+ // Reserve an entry for function entry.
+ live := bvalloc(nvars)
+ lv.livevars = append(lv.livevars, live)
+ }
+
+ for _, b := range lv.f.Blocks {
+ be := lv.blockEffects(b)
+
+ // Walk forward through the basic block instructions and
+ // allocate liveness maps for those instructions that need them.
+ for _, v := range b.Values {
+ if !lv.hasStackMap(v) {
+ continue
+ }
+
+ live := bvalloc(nvars)
+ lv.livevars = append(lv.livevars, live)
+ }
+
+ // walk backward, construct maps at each safe point
+ index := int32(len(lv.livevars) - 1)
+
+ liveout.Copy(be.liveout)
+ for i := len(b.Values) - 1; i >= 0; i-- {
+ v := b.Values[i]
+
+ if lv.hasStackMap(v) {
+ // Found an interesting instruction, record the
+ // corresponding liveness information.
+
+ live := &lv.livevars[index]
+ live.Or(*live, liveout)
+ live.Or(*live, livedefer) // only for non-entry safe points
+ index--
+ }
+
+ // Update liveness information.
+ pos, e := lv.valueEffects(v)
+ if e&varkill != 0 {
+ liveout.Unset(pos)
+ }
+ if e&uevar != 0 {
+ liveout.Set(pos)
+ }
+ }
+
+ if b == lv.f.Entry {
+ if index != 0 {
+ Fatalf("bad index for entry point: %v", index)
+ }
+
+ // Check to make sure only input variables are live.
+ for i, n := range lv.vars {
+ if !liveout.Get(int32(i)) {
+ continue
+ }
+ if n.Class() == PPARAM {
+ continue // ok
+ }
+ Fatalf("bad live variable at entry of %v: %L", lv.fn.Func.Nname, n)
+ }
+
+ // Record live variables.
+ live := &lv.livevars[index]
+ live.Or(*live, liveout)
+ }
+
+ // The liveness maps for this block are now complete. Compact them.
+ lv.compact(b)
+ }
+
+ // If we have an open-coded deferreturn call, make a liveness map for it.
+ if lv.fn.Func.OpenCodedDeferDisallowed() {
+ lv.livenessMap.deferreturn = LivenessDontCare
+ } else {
+ lv.livenessMap.deferreturn = LivenessIndex{
+ stackMapIndex: lv.stackMapSet.add(livedefer),
+ isUnsafePoint: false,
+ }
+ }
+
+ // Done compacting. Throw out the stack map set.
+ lv.stackMaps = lv.stackMapSet.extractUniqe()
+ lv.stackMapSet = bvecSet{}
+
+ // Useful sanity check: on entry to the function,
+ // the only things that can possibly be live are the
+ // input parameters.
+ for j, n := range lv.vars {
+ if n.Class() != PPARAM && lv.stackMaps[0].Get(int32(j)) {
+ lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Func.Nname, n)
+ }
+ }
+}
+
+// Compact coalesces identical bitmaps from lv.livevars into the sets
+// lv.stackMapSet.
+//
+// Compact clears lv.livevars.
+//
+// There are actually two lists of bitmaps, one list for the local variables and one
+// list for the function arguments. Both lists are indexed by the same PCDATA
+// index, so the corresponding pairs must be considered together when
+// merging duplicates. The argument bitmaps change much less often during
+// function execution than the local variable bitmaps, so it is possible that
+// we could introduce a separate PCDATA index for arguments vs locals and
+// then compact the set of argument bitmaps separately from the set of
+// local variable bitmaps. As of 2014-04-02, doing this to the godoc binary
+// is actually a net loss: we save about 50k of argument bitmaps but the new
+// PCDATA tables cost about 100k. So for now we keep using a single index for
+// both bitmap lists.
+func (lv *Liveness) compact(b *ssa.Block) {
+ pos := 0
+ if b == lv.f.Entry {
+ // Handle entry stack map.
+ lv.stackMapSet.add(lv.livevars[0])
+ pos++
+ }
+ for _, v := range b.Values {
+ hasStackMap := lv.hasStackMap(v)
+ isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
+ idx := LivenessIndex{StackMapDontCare, isUnsafePoint}
+ if hasStackMap {
+ idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos])
+ pos++
+ }
+ if hasStackMap || isUnsafePoint {
+ lv.livenessMap.set(v, idx)
+ }
+ }
+
+ // Reset livevars.
+ lv.livevars = lv.livevars[:0]
+}
+
+func (lv *Liveness) showlive(v *ssa.Value, live bvec) {
+ if debuglive == 0 || lv.fn.funcname() == "init" || strings.HasPrefix(lv.fn.funcname(), ".") {
+ return
+ }
+ if !(v == nil || v.Op.IsCall()) {
+ // Historically we only printed this information at
+ // calls. Keep doing so.
+ return
+ }
+ if live.IsEmpty() {
+ return
+ }
+
+ pos := lv.fn.Func.Nname.Pos
+ if v != nil {
+ pos = v.Pos
+ }
+
+ s := "live at "
+ if v == nil {
+ s += fmt.Sprintf("entry to %s:", lv.fn.funcname())
+ } else if sym, ok := v.Aux.(*ssa.AuxCall); ok && sym.Fn != nil {
+ fn := sym.Fn.Name
+ if pos := strings.Index(fn, "."); pos >= 0 {
+ fn = fn[pos+1:]
+ }
+ s += fmt.Sprintf("call to %s:", fn)
+ } else {
+ s += "indirect call:"
+ }
+
+ for j, n := range lv.vars {
+ if live.Get(int32(j)) {
+ s += fmt.Sprintf(" %v", n)
+ }
+ }
+
+ Warnl(pos, s)
+}
+
+func (lv *Liveness) printbvec(printed bool, name string, live bvec) bool {
+ if live.IsEmpty() {
+ return printed
+ }
+
+ if !printed {
+ fmt.Printf("\t")
+ } else {
+ fmt.Printf(" ")
+ }
+ fmt.Printf("%s=", name)
+
+ comma := ""
+ for i, n := range lv.vars {
+ if !live.Get(int32(i)) {
+ continue
+ }
+ fmt.Printf("%s%s", comma, n.Sym.Name)
+ comma = ","
+ }
+ return true
+}
+
+// printeffect is like printbvec, but for valueEffects.
+func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool) bool {
+ if !x {
+ return printed
+ }
+ if !printed {
+ fmt.Printf("\t")
+ } else {
+ fmt.Printf(" ")
+ }
+ fmt.Printf("%s=", name)
+ if x {
+ fmt.Printf("%s", lv.vars[pos].Sym.Name)
+ }
+
+ return true
+}
+
+// Prints the computed liveness information and inputs, for debugging.
+// This format synthesizes the information used during the multiple passes
+// into a single presentation.
+func (lv *Liveness) printDebug() {
+ fmt.Printf("liveness: %s\n", lv.fn.funcname())
+
+ for i, b := range lv.f.Blocks {
+ if i > 0 {
+ fmt.Printf("\n")
+ }
+
+ // bb#0 pred=1,2 succ=3,4
+ fmt.Printf("bb#%d pred=", b.ID)
+ for j, pred := range b.Preds {
+ if j > 0 {
+ fmt.Printf(",")
+ }
+ fmt.Printf("%d", pred.Block().ID)
+ }
+ fmt.Printf(" succ=")
+ for j, succ := range b.Succs {
+ if j > 0 {
+ fmt.Printf(",")
+ }
+ fmt.Printf("%d", succ.Block().ID)
+ }
+ fmt.Printf("\n")
+
+ be := lv.blockEffects(b)
+
+ // initial settings
+ printed := false
+ printed = lv.printbvec(printed, "uevar", be.uevar)
+ printed = lv.printbvec(printed, "livein", be.livein)
+ if printed {
+ fmt.Printf("\n")
+ }
+
+ // program listing, with individual effects listed
+
+ if b == lv.f.Entry {
+ live := lv.stackMaps[0]
+ fmt.Printf("(%s) function entry\n", linestr(lv.fn.Func.Nname.Pos))
+ fmt.Printf("\tlive=")
+ printed = false
+ for j, n := range lv.vars {
+ if !live.Get(int32(j)) {
+ continue
+ }
+ if printed {
+ fmt.Printf(",")
+ }
+ fmt.Printf("%v", n)
+ printed = true
+ }
+ fmt.Printf("\n")
+ }
+
+ for _, v := range b.Values {
+ fmt.Printf("(%s) %v\n", linestr(v.Pos), v.LongString())
+
+ pcdata := lv.livenessMap.Get(v)
+
+ pos, effect := lv.valueEffects(v)
+ printed = false
+ printed = lv.printeffect(printed, "uevar", pos, effect&uevar != 0)
+ printed = lv.printeffect(printed, "varkill", pos, effect&varkill != 0)
+ if printed {
+ fmt.Printf("\n")
+ }
+
+ if pcdata.StackMapValid() {
+ fmt.Printf("\tlive=")
+ printed = false
+ if pcdata.StackMapValid() {
+ live := lv.stackMaps[pcdata.stackMapIndex]
+ for j, n := range lv.vars {
+ if !live.Get(int32(j)) {
+ continue
+ }
+ if printed {
+ fmt.Printf(",")
+ }
+ fmt.Printf("%v", n)
+ printed = true
+ }
+ }
+ fmt.Printf("\n")
+ }
+
+ if pcdata.isUnsafePoint {
+ fmt.Printf("\tunsafe-point\n")
+ }
+ }
+
+ // bb bitsets
+ fmt.Printf("end\n")
+ printed = false
+ printed = lv.printbvec(printed, "varkill", be.varkill)
+ printed = lv.printbvec(printed, "liveout", be.liveout)
+ if printed {
+ fmt.Printf("\n")
+ }
+ }
+
+ fmt.Printf("\n")
+}
+
+// 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
+// remaining bytes are the raw bitmaps.
+func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) {
+ // Size args bitmaps to be just large enough to hold the largest pointer.
+ // First, find the largest Xoffset node we care about.
+ // (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
+ var maxArgNode *Node
+ for _, n := range lv.vars {
+ switch n.Class() {
+ case PPARAM, PPARAMOUT:
+ if maxArgNode == nil || n.Xoffset > maxArgNode.Xoffset {
+ maxArgNode = n
+ }
+ }
+ }
+ // Next, find the offset of the largest pointer in the largest node.
+ var maxArgs int64
+ if maxArgNode != nil {
+ maxArgs = maxArgNode.Xoffset + typeptrdata(maxArgNode.Type)
+ }
+
+ // Size locals bitmaps to be stkptrsize sized.
+ // We cannot shrink them to only hold the largest pointer,
+ // because their size is used to calculate the beginning
+ // of the local variables frame.
+ // Further discussion in https://golang.org/cl/104175.
+ // TODO: consider trimming leading zeros.
+ // This would require shifting all bitmaps.
+ maxLocals := lv.stkptrsize
+
+ // Temporary symbols for encoding bitmaps.
+ var argsSymTmp, liveSymTmp obj.LSym
+
+ args := bvalloc(int32(maxArgs / int64(Widthptr)))
+ aoff := duint32(&argsSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
+ aoff = duint32(&argsSymTmp, aoff, uint32(args.n)) // number of bits in each bitmap
+
+ locals := bvalloc(int32(maxLocals / int64(Widthptr)))
+ loff := duint32(&liveSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
+ loff = duint32(&liveSymTmp, loff, uint32(locals.n)) // number of bits in each bitmap
+
+ for _, live := range lv.stackMaps {
+ args.Clear()
+ locals.Clear()
+
+ lv.pointerMap(live, lv.vars, args, locals)
+
+ aoff = dbvec(&argsSymTmp, aoff, args)
+ loff = dbvec(&liveSymTmp, loff, locals)
+ }
+
+ // Give these LSyms content-addressable names,
+ // so that they can be de-duplicated.
+ // This provides significant binary size savings.
+ //
+ // These symbols will be added to Ctxt.Data by addGCLocals
+ // after parallel compilation is done.
+ makeSym := func(tmpSym *obj.LSym) *obj.LSym {
+ return Ctxt.LookupInit(fmt.Sprintf("gclocals·%x", md5.Sum(tmpSym.P)), func(lsym *obj.LSym) {
+ lsym.P = tmpSym.P
+ lsym.Set(obj.AttrContentAddressable, true)
+ })
+ }
+ return makeSym(&argsSymTmp), makeSym(&liveSymTmp)
+}
+
+// Entry pointer for liveness analysis. Solves for the liveness of
+// pointer variables in the function and emits a runtime data
+// structure read by the garbage collector.
+// Returns a map from GC safe points to their corresponding stack map index.
+func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
+ // Construct the global liveness state.
+ vars, idx := getvariables(e.curfn)
+ lv := newliveness(e.curfn, f, vars, idx, e.stkptrsize)
+
+ // Run the dataflow framework.
+ lv.prologue()
+ lv.solve()
+ lv.epilogue()
+ if debuglive > 0 {
+ lv.showlive(nil, lv.stackMaps[0])
+ for _, b := range f.Blocks {
+ for _, val := range b.Values {
+ if idx := lv.livenessMap.Get(val); idx.StackMapValid() {
+ lv.showlive(val, lv.stackMaps[idx.stackMapIndex])
+ }
+ }
+ }
+ }
+ if debuglive >= 2 {
+ lv.printDebug()
+ }
+
+ // Update the function cache.
+ {
+ cache := f.Cache.Liveness.(*livenessFuncCache)
+ if cap(lv.be) < 2000 { // Threshold from ssa.Cache slices.
+ for i := range lv.be {
+ lv.be[i] = BlockEffects{}
+ }
+ cache.be = lv.be
+ }
+ if len(lv.livenessMap.vals) < 2000 {
+ cache.livenessMap = lv.livenessMap
+ }
+ }
+
+ // Emit the live pointer map data structures
+ ls := e.curfn.Func.lsym
+ fninfo := ls.Func()
+ fninfo.GCArgs, fninfo.GCLocals = lv.emit()
+
+ p := pp.Prog(obj.AFUNCDATA)
+ Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = fninfo.GCArgs
+
+ p = pp.Prog(obj.AFUNCDATA)
+ Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = fninfo.GCLocals
+
+ return lv.livenessMap
+}
+
+// isfat reports whether a variable of type t needs multiple assignments to initialize.
+// For example:
+//
+// type T struct { x, y int }
+// x := T{x: 0, y: 1}
+//
+// Then we need:
+//
+// var t T
+// t.x = 0
+// t.y = 1
+//
+// to fully initialize t.
+func isfat(t *types.Type) bool {
+ if t != nil {
+ switch t.Etype {
+ case TSLICE, TSTRING,
+ TINTER: // maybe remove later
+ return true
+ case TARRAY:
+ // Array of 1 element, check if element is fat
+ if t.NumElem() == 1 {
+ return isfat(t.Elem())
+ }
+ return true
+ case TSTRUCT:
+ // Struct with 1 field, check if field is fat
+ if t.NumFields() == 1 {
+ return isfat(t.Field(0).Type)
+ }
+ return true
+ }
+ }
+
+ return false
+}
diff --git a/src/cmd/compile/internal/gc/pprof.go b/src/cmd/compile/internal/gc/pprof.go
new file mode 100644
index 0000000..256c659
--- /dev/null
+++ b/src/cmd/compile/internal/gc/pprof.go
@@ -0,0 +1,13 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.8
+
+package gc
+
+import "runtime"
+
+func startMutexProfiling() {
+ runtime.SetMutexProfileFraction(1)
+}
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
new file mode 100644
index 0000000..3552617
--- /dev/null
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -0,0 +1,93 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "cmd/internal/sys"
+)
+
+// The racewalk pass is currently handled in three parts.
+//
+// First, for flag_race, it inserts calls to racefuncenter and
+// racefuncexit at the start and end (respectively) of each
+// function. This is handled below.
+//
+// Second, during buildssa, it inserts appropriate instrumentation
+// calls immediately before each memory load or store. This is handled
+// by the (*state).instrument method in ssa.go, so here we just set
+// the Func.InstrumentBody flag as needed. For background on why this
+// is done during SSA construction rather than a separate SSA pass,
+// see issue #19054.
+//
+// Third we remove calls to racefuncenter and racefuncexit, for leaf
+// functions without instrumented operations. This is done as part of
+// ssa opt pass via special rule.
+
+// TODO(dvyukov): do not instrument initialization as writes:
+// a := make([]int, 10)
+
+// Do not instrument the following packages at all,
+// at best instrumentation would cause infinite recursion.
+var omit_pkgs = []string{
+ "runtime/internal/atomic",
+ "runtime/internal/sys",
+ "runtime/internal/math",
+ "runtime",
+ "runtime/race",
+ "runtime/msan",
+ "internal/cpu",
+}
+
+// Don't insert racefuncenterfp/racefuncexit into the following packages.
+// Memory accesses in the packages are either uninteresting or will cause false positives.
+var norace_inst_pkgs = []string{"sync", "sync/atomic"}
+
+func ispkgin(pkgs []string) bool {
+ if myimportpath != "" {
+ for _, p := range pkgs {
+ if myimportpath == p {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+func instrument(fn *Node) {
+ if fn.Func.Pragma&Norace != 0 {
+ return
+ }
+
+ if !flag_race || !ispkgin(norace_inst_pkgs) {
+ fn.Func.SetInstrumentBody(true)
+ }
+
+ if flag_race {
+ lno := lineno
+ lineno = src.NoXPos
+
+ if thearch.LinkArch.Arch.Family != sys.AMD64 {
+ fn.Func.Enter.Prepend(mkcall("racefuncenterfp", nil, nil))
+ fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
+ } else {
+
+ // nodpc is the PC of the caller as extracted by
+ // getcallerpc. We use -widthptr(FP) for x86.
+ // This only works for amd64. This will not
+ // work on arm or others that might support
+ // race in the future.
+ nodpc := nodfp.copy()
+ nodpc.Type = types.Types[TUINTPTR]
+ nodpc.Xoffset = int64(-Widthptr)
+ fn.Func.Dcl = append(fn.Func.Dcl, nodpc)
+ fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc))
+ fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
+ }
+ lineno = lno
+ }
+}
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
new file mode 100644
index 0000000..1b4d765
--- /dev/null
+++ b/src/cmd/compile/internal/gc/range.go
@@ -0,0 +1,628 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/sys"
+ "unicode/utf8"
+)
+
+// range
+func typecheckrange(n *Node) {
+ // Typechecking order is important here:
+ // 0. first typecheck range expression (slice/map/chan),
+ // it is evaluated only once and so logically it is not part of the loop.
+ // 1. typecheck produced values,
+ // this part can declare new vars and so it must be typechecked before body,
+ // because body can contain a closure that captures the vars.
+ // 2. decldepth++ to denote loop body.
+ // 3. typecheck body.
+ // 4. decldepth--.
+ typecheckrangeExpr(n)
+
+ // second half of dance, the first half being typecheckrangeExpr
+ n.SetTypecheck(1)
+ ls := n.List.Slice()
+ for i1, n1 := range ls {
+ if n1.Typecheck() == 0 {
+ ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
+ }
+ }
+
+ decldepth++
+ typecheckslice(n.Nbody.Slice(), ctxStmt)
+ decldepth--
+}
+
+func typecheckrangeExpr(n *Node) {
+ n.Right = typecheck(n.Right, ctxExpr)
+
+ t := n.Right.Type
+ if t == nil {
+ return
+ }
+ // delicate little dance. see typecheckas2
+ ls := n.List.Slice()
+ for i1, n1 := range ls {
+ if n1.Name == nil || n1.Name.Defn != n {
+ ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
+ }
+ }
+
+ if t.IsPtr() && t.Elem().IsArray() {
+ t = t.Elem()
+ }
+ n.Type = t
+
+ var t1, t2 *types.Type
+ toomany := false
+ switch t.Etype {
+ default:
+ yyerrorl(n.Pos, "cannot range over %L", n.Right)
+ return
+
+ case TARRAY, TSLICE:
+ t1 = types.Types[TINT]
+ t2 = t.Elem()
+
+ case TMAP:
+ t1 = t.Key()
+ t2 = t.Elem()
+
+ case TCHAN:
+ if !t.ChanDir().CanRecv() {
+ yyerrorl(n.Pos, "invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
+ return
+ }
+
+ t1 = t.Elem()
+ t2 = nil
+ if n.List.Len() == 2 {
+ toomany = true
+ }
+
+ case TSTRING:
+ t1 = types.Types[TINT]
+ t2 = types.Runetype
+ }
+
+ if n.List.Len() > 2 || toomany {
+ yyerrorl(n.Pos, "too many variables in range")
+ }
+
+ var v1, v2 *Node
+ if n.List.Len() != 0 {
+ v1 = n.List.First()
+ }
+ if n.List.Len() > 1 {
+ v2 = n.List.Second()
+ }
+
+ // this is not only an optimization but also a requirement in the spec.
+ // "if the second iteration variable is the blank identifier, the range
+ // clause is equivalent to the same clause with only the first variable
+ // present."
+ if v2.isBlank() {
+ if v1 != nil {
+ n.List.Set1(v1)
+ }
+ v2 = nil
+ }
+
+ if v1 != nil {
+ if v1.Name != nil && v1.Name.Defn == n {
+ v1.Type = t1
+ } else if v1.Type != nil {
+ if op, why := assignop(t1, v1.Type); op == OXXX {
+ yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
+ }
+ }
+ checkassign(n, v1)
+ }
+
+ if v2 != nil {
+ if v2.Name != nil && v2.Name.Defn == n {
+ v2.Type = t2
+ } else if v2.Type != nil {
+ if op, why := assignop(t2, v2.Type); op == OXXX {
+ yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
+ }
+ }
+ checkassign(n, v2)
+ }
+}
+
+func cheapComputableIndex(width int64) bool {
+ switch thearch.LinkArch.Family {
+ // MIPS does not have R+R addressing
+ // Arm64 may lack ability to generate this code in our assembler,
+ // but the architecture supports it.
+ case sys.PPC64, sys.S390X:
+ return width == 1
+ case sys.AMD64, sys.I386, sys.ARM64, sys.ARM:
+ switch width {
+ case 1, 2, 4, 8:
+ return true
+ }
+ }
+ return false
+}
+
+// walkrange transforms various forms of ORANGE into
+// simpler forms. The result must be assigned back to n.
+// Node n may also be modified in place, and may also be
+// the returned node.
+func walkrange(n *Node) *Node {
+ if isMapClear(n) {
+ m := n.Right
+ lno := setlineno(m)
+ n = mapClear(m)
+ lineno = lno
+ return n
+ }
+
+ // variable name conventions:
+ // ohv1, hv1, hv2: hidden (old) val 1, 2
+ // ha, hit: hidden aggregate, iterator
+ // hn, hp: hidden len, pointer
+ // hb: hidden bool
+ // a, v1, v2: not hidden aggregate, val 1, 2
+
+ t := n.Type
+
+ a := n.Right
+ lno := setlineno(a)
+ n.Right = nil
+
+ var v1, v2 *Node
+ l := n.List.Len()
+ if l > 0 {
+ v1 = n.List.First()
+ }
+
+ if l > 1 {
+ v2 = n.List.Second()
+ }
+
+ if v2.isBlank() {
+ v2 = nil
+ }
+
+ if v1.isBlank() && v2 == nil {
+ v1 = nil
+ }
+
+ if v1 == nil && v2 != nil {
+ Fatalf("walkrange: v2 != nil while v1 == nil")
+ }
+
+ // n.List has no meaning anymore, clear it
+ // to avoid erroneous processing by racewalk.
+ n.List.Set(nil)
+
+ var ifGuard *Node
+
+ translatedLoopOp := OFOR
+
+ var body []*Node
+ var init []*Node
+ switch t.Etype {
+ default:
+ Fatalf("walkrange")
+
+ case TARRAY, TSLICE:
+ if arrayClear(n, v1, v2, a) {
+ lineno = lno
+ return n
+ }
+
+ // order.stmt arranged for a copy of the array/slice variable if needed.
+ ha := a
+
+ hv1 := temp(types.Types[TINT])
+ hn := temp(types.Types[TINT])
+
+ init = append(init, nod(OAS, hv1, nil))
+ init = append(init, nod(OAS, hn, nod(OLEN, ha, nil)))
+
+ n.Left = nod(OLT, hv1, hn)
+ n.Right = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)))
+
+ // for range ha { body }
+ if v1 == nil {
+ break
+ }
+
+ // for v1 := range ha { body }
+ if v2 == nil {
+ body = []*Node{nod(OAS, v1, hv1)}
+ break
+ }
+
+ // for v1, v2 := range ha { body }
+ if cheapComputableIndex(n.Type.Elem().Width) {
+ // v1, v2 = hv1, ha[hv1]
+ tmp := nod(OINDEX, ha, hv1)
+ tmp.SetBounded(true)
+ // Use OAS2 to correctly handle assignments
+ // of the form "v1, a[v1] := range".
+ a := nod(OAS2, nil, nil)
+ a.List.Set2(v1, v2)
+ a.Rlist.Set2(hv1, tmp)
+ body = []*Node{a}
+ break
+ }
+
+ // TODO(austin): OFORUNTIL is a strange beast, but is
+ // necessary for expressing the control flow we need
+ // while also making "break" and "continue" work. It
+ // would be nice to just lower ORANGE during SSA, but
+ // racewalk needs to see many of the operations
+ // involved in ORANGE's implementation. If racewalk
+ // moves into SSA, consider moving ORANGE into SSA and
+ // eliminating OFORUNTIL.
+
+ // TODO(austin): OFORUNTIL inhibits bounds-check
+ // elimination on the index variable (see #20711).
+ // Enhance the prove pass to understand this.
+ ifGuard = nod(OIF, nil, nil)
+ ifGuard.Left = nod(OLT, hv1, hn)
+ translatedLoopOp = OFORUNTIL
+
+ hp := temp(types.NewPtr(n.Type.Elem()))
+ tmp := nod(OINDEX, ha, nodintconst(0))
+ tmp.SetBounded(true)
+ init = append(init, nod(OAS, hp, nod(OADDR, tmp, nil)))
+
+ // Use OAS2 to correctly handle assignments
+ // of the form "v1, a[v1] := range".
+ a := nod(OAS2, nil, nil)
+ a.List.Set2(v1, v2)
+ a.Rlist.Set2(hv1, nod(ODEREF, hp, nil))
+ body = append(body, a)
+
+ // Advance pointer as part of the late increment.
+ //
+ // This runs *after* the condition check, so we know
+ // advancing the pointer is safe and won't go past the
+ // end of the allocation.
+ a = nod(OAS, hp, addptr(hp, t.Elem().Width))
+ a = typecheck(a, ctxStmt)
+ n.List.Set1(a)
+
+ case TMAP:
+ // order.stmt allocated the iterator for us.
+ // we only use a once, so no copy needed.
+ ha := a
+
+ hit := prealloc[n]
+ th := hit.Type
+ n.Left = nil
+ keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter
+ elemsym := th.Field(1).Sym // ditto
+
+ fn := syslook("mapiterinit")
+
+ fn = substArgTypes(fn, t.Key(), t.Elem(), th)
+ init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nod(OADDR, hit, nil)))
+ n.Left = nod(ONE, nodSym(ODOT, hit, keysym), nodnil())
+
+ fn = syslook("mapiternext")
+ fn = substArgTypes(fn, th)
+ n.Right = mkcall1(fn, nil, nil, nod(OADDR, hit, nil))
+
+ key := nodSym(ODOT, hit, keysym)
+ key = nod(ODEREF, key, nil)
+ if v1 == nil {
+ body = nil
+ } else if v2 == nil {
+ body = []*Node{nod(OAS, v1, key)}
+ } else {
+ elem := nodSym(ODOT, hit, elemsym)
+ elem = nod(ODEREF, elem, nil)
+ a := nod(OAS2, nil, nil)
+ a.List.Set2(v1, v2)
+ a.Rlist.Set2(key, elem)
+ body = []*Node{a}
+ }
+
+ case TCHAN:
+ // order.stmt arranged for a copy of the channel variable.
+ ha := a
+
+ n.Left = nil
+
+ hv1 := temp(t.Elem())
+ hv1.SetTypecheck(1)
+ if t.Elem().HasPointers() {
+ init = append(init, nod(OAS, hv1, nil))
+ }
+ hb := temp(types.Types[TBOOL])
+
+ n.Left = nod(ONE, hb, nodbool(false))
+ a := nod(OAS2RECV, nil, nil)
+ a.SetTypecheck(1)
+ a.List.Set2(hv1, hb)
+ a.Right = nod(ORECV, ha, nil)
+ n.Left.Ninit.Set1(a)
+ if v1 == nil {
+ body = nil
+ } else {
+ 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))
+
+ case TSTRING:
+ // Transform string range statements like "for v1, v2 = range a" into
+ //
+ // ha := a
+ // for hv1 := 0; hv1 < len(ha); {
+ // hv1t := hv1
+ // hv2 := rune(ha[hv1])
+ // if hv2 < utf8.RuneSelf {
+ // hv1++
+ // } else {
+ // hv2, hv1 = decoderune(ha, hv1)
+ // }
+ // v1, v2 = hv1t, hv2
+ // // original body
+ // }
+
+ // order.stmt arranged for a copy of the string variable.
+ ha := a
+
+ hv1 := temp(types.Types[TINT])
+ hv1t := temp(types.Types[TINT])
+ hv2 := temp(types.Runetype)
+
+ // hv1 := 0
+ init = append(init, nod(OAS, hv1, nil))
+
+ // hv1 < len(ha)
+ n.Left = nod(OLT, hv1, nod(OLEN, ha, nil))
+
+ if v1 != nil {
+ // hv1t = hv1
+ body = append(body, nod(OAS, hv1t, hv1))
+ }
+
+ // hv2 := rune(ha[hv1])
+ nind := nod(OINDEX, ha, hv1)
+ nind.SetBounded(true)
+ body = append(body, nod(OAS, hv2, conv(nind, types.Runetype)))
+
+ // if hv2 < utf8.RuneSelf
+ nif := nod(OIF, nil, nil)
+ nif.Left = nod(OLT, hv2, 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 v1 != nil {
+ if v2 != nil {
+ // v1, v2 = hv1t, hv2
+ a := nod(OAS2, nil, nil)
+ a.List.Set2(v1, v2)
+ a.Rlist.Set2(hv1t, hv2)
+ body = append(body, a)
+ } else {
+ // v1 = hv1t
+ body = append(body, nod(OAS, v1, hv1t))
+ }
+ }
+ }
+
+ n.Op = translatedLoopOp
+ typecheckslice(init, ctxStmt)
+
+ if ifGuard != nil {
+ ifGuard.Ninit.Append(init...)
+ ifGuard = typecheck(ifGuard, ctxStmt)
+ } else {
+ n.Ninit.Append(init...)
+ }
+
+ typecheckslice(n.Left.Ninit.Slice(), ctxStmt)
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ n.Right = typecheck(n.Right, ctxStmt)
+ typecheckslice(body, ctxStmt)
+ n.Nbody.Prepend(body...)
+
+ if ifGuard != nil {
+ ifGuard.Nbody.Set1(n)
+ n = ifGuard
+ }
+
+ n = walkstmt(n)
+
+ lineno = lno
+ return n
+}
+
+// isMapClear checks if n is of the form:
+//
+// for k := range m {
+// delete(m, k)
+// }
+//
+// where == for keys of map m is reflexive.
+func isMapClear(n *Node) bool {
+ if Debug.N != 0 || instrumenting {
+ return false
+ }
+
+ if n.Op != ORANGE || n.Type.Etype != TMAP || n.List.Len() != 1 {
+ return false
+ }
+
+ k := n.List.First()
+ if k == nil || k.isBlank() {
+ return false
+ }
+
+ // Require k to be a new variable name.
+ if k.Name == nil || k.Name.Defn != n {
+ return false
+ }
+
+ if n.Nbody.Len() != 1 {
+ return false
+ }
+
+ stmt := n.Nbody.First() // only stmt in body
+ if stmt == nil || stmt.Op != ODELETE {
+ return false
+ }
+
+ m := n.Right
+ if !samesafeexpr(stmt.List.First(), m) || !samesafeexpr(stmt.List.Second(), k) {
+ return false
+ }
+
+ // Keys where equality is not reflexive can not be deleted from maps.
+ if !isreflexive(m.Type.Key()) {
+ return false
+ }
+
+ return true
+}
+
+// mapClear constructs a call to runtime.mapclear for the map m.
+func mapClear(m *Node) *Node {
+ t := m.Type
+
+ // instantiate mapclear(typ *type, hmap map[any]any)
+ fn := syslook("mapclear")
+ fn = substArgTypes(fn, t.Key(), t.Elem())
+ n := mkcall1(fn, nil, nil, typename(t), m)
+
+ n = typecheck(n, ctxStmt)
+ n = walkstmt(n)
+
+ return n
+}
+
+// Lower n into runtime·memclr if possible, for
+// fast zeroing of slices and arrays (issue 5373).
+// Look for instances of
+//
+// for i := range a {
+// a[i] = zero
+// }
+//
+// in which the evaluation of a is side-effect-free.
+//
+// Parameters are as in walkrange: "for v1, v2 = range a".
+func arrayClear(n, v1, v2, a *Node) bool {
+ if Debug.N != 0 || instrumenting {
+ return false
+ }
+
+ if v1 == nil || v2 != nil {
+ return false
+ }
+
+ if n.Nbody.Len() != 1 || n.Nbody.First() == nil {
+ return false
+ }
+
+ stmt := n.Nbody.First() // only stmt in body
+ if stmt.Op != OAS || stmt.Left.Op != OINDEX {
+ return false
+ }
+
+ if !samesafeexpr(stmt.Left.Left, a) || !samesafeexpr(stmt.Left.Right, v1) {
+ return false
+ }
+
+ elemsize := n.Type.Elem().Width
+ if elemsize <= 0 || !isZero(stmt.Right) {
+ return false
+ }
+
+ // Convert to
+ // if len(a) != 0 {
+ // hp = &a[0]
+ // hn = len(a)*sizeof(elem(a))
+ // 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))
+
+ // hp = &a[0]
+ hp := temp(types.Types[TUNSAFEPTR])
+
+ tmp := nod(OINDEX, a, nodintconst(0))
+ tmp.SetBounded(true)
+ tmp = nod(OADDR, tmp, nil)
+ tmp = convnop(tmp, types.Types[TUNSAFEPTR])
+ n.Nbody.Append(nod(OAS, hp, tmp))
+
+ // hn = len(a) * sizeof(elem(a))
+ hn := temp(types.Types[TUINTPTR])
+
+ tmp = nod(OLEN, a, nil)
+ tmp = nod(OMUL, tmp, nodintconst(elemsize))
+ tmp = conv(tmp, types.Types[TUINTPTR])
+ n.Nbody.Append(nod(OAS, hn, tmp))
+
+ var fn *Node
+ if a.Type.Elem().HasPointers() {
+ // memclrHasPointers(hp, hn)
+ Curfn.Func.setWBPos(stmt.Pos)
+ 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)))
+
+ n.Nbody.Append(v1)
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ typecheckslice(n.Nbody.Slice(), ctxStmt)
+ n = walkstmt(n)
+ return true
+}
+
+// addptr returns (*T)(uintptr(p) + n).
+func addptr(p *Node, n int64) *Node {
+ t := p.Type
+
+ p = nod(OCONVNOP, p, nil)
+ p.Type = types.Types[TUINTPTR]
+
+ p = nod(OADD, p, nodintconst(n))
+
+ p = nod(OCONVNOP, p, nil)
+ p.Type = t
+
+ return p
+}
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
new file mode 100644
index 0000000..9401eba
--- /dev/null
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -0,0 +1,1901 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/gcprog"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+ "fmt"
+ "os"
+ "sort"
+ "strings"
+ "sync"
+)
+
+type itabEntry struct {
+ t, itype *types.Type
+ lsym *obj.LSym // symbol of the itab itself
+
+ // symbols of each method in
+ // the itab, sorted by byte offset;
+ // filled in by peekitabs
+ entries []*obj.LSym
+}
+
+type ptabEntry struct {
+ s *types.Sym
+ t *types.Type
+}
+
+// runtime interface and reflection data structures
+var (
+ signatmu sync.Mutex // protects signatset and signatslice
+ signatset = make(map[*types.Type]struct{})
+ signatslice []*types.Type
+
+ itabs []itabEntry
+ ptabs []ptabEntry
+)
+
+type Sig struct {
+ name *types.Sym
+ isym *types.Sym
+ tsym *types.Sym
+ type_ *types.Type
+ mtype *types.Type
+}
+
+// Builds a type representing a Bucket structure for
+// the given map type. This type is not visible to users -
+// we include only enough information to generate a correct GC
+// program for it.
+// Make sure this stays in sync with runtime/map.go.
+const (
+ BUCKETSIZE = 8
+ MAXKEYSIZE = 128
+ MAXELEMSIZE = 128
+)
+
+func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{})
+func imethodSize() int { return 4 + 4 } // Sizeof(runtime.imethod{})
+func commonSize() int { return 4*Widthptr + 8 + 8 } // Sizeof(runtime._type{})
+
+func uncommonSize(t *types.Type) int { // Sizeof(runtime.uncommontype{})
+ if t.Sym == nil && len(methods(t)) == 0 {
+ return 0
+ }
+ return 4 + 2 + 2 + 4 + 4
+}
+
+func makefield(name string, t *types.Type) *types.Field {
+ f := types.NewField()
+ f.Type = t
+ f.Sym = (*types.Pkg)(nil).Lookup(name)
+ return f
+}
+
+// bmap makes the map bucket type given the type of the map.
+func bmap(t *types.Type) *types.Type {
+ if t.MapType().Bucket != nil {
+ return t.MapType().Bucket
+ }
+
+ bucket := types.New(TSTRUCT)
+ keytype := t.Key()
+ elemtype := t.Elem()
+ dowidth(keytype)
+ dowidth(elemtype)
+ if keytype.Width > MAXKEYSIZE {
+ keytype = types.NewPtr(keytype)
+ }
+ if elemtype.Width > MAXELEMSIZE {
+ elemtype = types.NewPtr(elemtype)
+ }
+
+ field := make([]*types.Field, 0, 5)
+
+ // The first field is: uint8 topbits[BUCKETSIZE].
+ arr := types.NewArray(types.Types[TUINT8], BUCKETSIZE)
+ field = append(field, makefield("topbits", arr))
+
+ arr = types.NewArray(keytype, BUCKETSIZE)
+ arr.SetNoalg(true)
+ keys := makefield("keys", arr)
+ field = append(field, keys)
+
+ arr = types.NewArray(elemtype, BUCKETSIZE)
+ arr.SetNoalg(true)
+ elems := makefield("elems", arr)
+ field = append(field, elems)
+
+ // If keys and elems have no pointers, the map implementation
+ // can keep a list of overflow pointers on the side so that
+ // buckets can be marked as having no pointers.
+ // Arrange for the bucket to have no pointers by changing
+ // the type of the overflow field to uintptr in this case.
+ // See comment on hmap.overflow in runtime/map.go.
+ otyp := types.NewPtr(bucket)
+ if !elemtype.HasPointers() && !keytype.HasPointers() {
+ otyp = types.Types[TUINTPTR]
+ }
+ overflow := makefield("overflow", otyp)
+ field = append(field, overflow)
+
+ // link up fields
+ bucket.SetNoalg(true)
+ bucket.SetFields(field[:])
+ dowidth(bucket)
+
+ // Check invariants that map code depends on.
+ if !IsComparable(t.Key()) {
+ Fatalf("unsupported map key type for %v", t)
+ }
+ if BUCKETSIZE < 8 {
+ Fatalf("bucket size too small for proper alignment")
+ }
+ if keytype.Align > BUCKETSIZE {
+ Fatalf("key align too big for %v", t)
+ }
+ if elemtype.Align > BUCKETSIZE {
+ Fatalf("elem align too big for %v", t)
+ }
+ if keytype.Width > MAXKEYSIZE {
+ Fatalf("key size to large for %v", t)
+ }
+ if elemtype.Width > MAXELEMSIZE {
+ Fatalf("elem size to large for %v", t)
+ }
+ if t.Key().Width > MAXKEYSIZE && !keytype.IsPtr() {
+ Fatalf("key indirect incorrect for %v", t)
+ }
+ if t.Elem().Width > MAXELEMSIZE && !elemtype.IsPtr() {
+ Fatalf("elem indirect incorrect for %v", t)
+ }
+ if keytype.Width%int64(keytype.Align) != 0 {
+ Fatalf("key size not a multiple of key align for %v", t)
+ }
+ if elemtype.Width%int64(elemtype.Align) != 0 {
+ Fatalf("elem size not a multiple of elem align for %v", t)
+ }
+ if bucket.Align%keytype.Align != 0 {
+ Fatalf("bucket align not multiple of key align %v", t)
+ }
+ if bucket.Align%elemtype.Align != 0 {
+ Fatalf("bucket align not multiple of elem align %v", t)
+ }
+ if keys.Offset%int64(keytype.Align) != 0 {
+ Fatalf("bad alignment of keys in bmap for %v", t)
+ }
+ if elems.Offset%int64(elemtype.Align) != 0 {
+ Fatalf("bad alignment of elems in bmap for %v", t)
+ }
+
+ // Double-check that overflow field is final memory in struct,
+ // with no padding at end.
+ if overflow.Offset != bucket.Width-int64(Widthptr) {
+ Fatalf("bad offset of overflow in bmap for %v", t)
+ }
+
+ t.MapType().Bucket = bucket
+
+ bucket.StructType().Map = t
+ return bucket
+}
+
+// hmap builds a type representing a Hmap structure for the given map type.
+// Make sure this stays in sync with runtime/map.go.
+func hmap(t *types.Type) *types.Type {
+ if t.MapType().Hmap != nil {
+ return t.MapType().Hmap
+ }
+
+ bmap := bmap(t)
+
+ // build a struct:
+ // type hmap struct {
+ // count int
+ // flags uint8
+ // B uint8
+ // noverflow uint16
+ // hash0 uint32
+ // buckets *bmap
+ // oldbuckets *bmap
+ // nevacuate uintptr
+ // extra unsafe.Pointer // *mapextra
+ // }
+ // must match runtime/map.go:hmap.
+ fields := []*types.Field{
+ makefield("count", types.Types[TINT]),
+ makefield("flags", types.Types[TUINT8]),
+ makefield("B", types.Types[TUINT8]),
+ makefield("noverflow", types.Types[TUINT16]),
+ makefield("hash0", types.Types[TUINT32]), // Used in walk.go for OMAKEMAP.
+ makefield("buckets", types.NewPtr(bmap)), // Used in walk.go for OMAKEMAP.
+ makefield("oldbuckets", types.NewPtr(bmap)),
+ makefield("nevacuate", types.Types[TUINTPTR]),
+ makefield("extra", types.Types[TUNSAFEPTR]),
+ }
+
+ hmap := types.New(TSTRUCT)
+ hmap.SetNoalg(true)
+ hmap.SetFields(fields)
+ dowidth(hmap)
+
+ // The size of hmap should be 48 bytes on 64 bit
+ // and 28 bytes on 32 bit platforms.
+ if size := int64(8 + 5*Widthptr); hmap.Width != size {
+ Fatalf("hmap size not correct: got %d, want %d", hmap.Width, size)
+ }
+
+ t.MapType().Hmap = hmap
+ hmap.StructType().Map = t
+ return hmap
+}
+
+// hiter builds a type representing an Hiter structure for the given map type.
+// Make sure this stays in sync with runtime/map.go.
+func hiter(t *types.Type) *types.Type {
+ if t.MapType().Hiter != nil {
+ return t.MapType().Hiter
+ }
+
+ hmap := hmap(t)
+ bmap := bmap(t)
+
+ // build a struct:
+ // type hiter struct {
+ // key *Key
+ // elem *Elem
+ // t unsafe.Pointer // *MapType
+ // h *hmap
+ // buckets *bmap
+ // bptr *bmap
+ // overflow unsafe.Pointer // *[]*bmap
+ // oldoverflow unsafe.Pointer // *[]*bmap
+ // startBucket uintptr
+ // offset uint8
+ // wrapped bool
+ // B uint8
+ // i uint8
+ // bucket uintptr
+ // checkBucket uintptr
+ // }
+ // must match runtime/map.go:hiter.
+ fields := []*types.Field{
+ makefield("key", types.NewPtr(t.Key())), // Used in range.go for TMAP.
+ makefield("elem", types.NewPtr(t.Elem())), // Used in range.go for TMAP.
+ makefield("t", types.Types[TUNSAFEPTR]),
+ makefield("h", types.NewPtr(hmap)),
+ makefield("buckets", types.NewPtr(bmap)),
+ makefield("bptr", types.NewPtr(bmap)),
+ makefield("overflow", types.Types[TUNSAFEPTR]),
+ makefield("oldoverflow", types.Types[TUNSAFEPTR]),
+ makefield("startBucket", types.Types[TUINTPTR]),
+ makefield("offset", types.Types[TUINT8]),
+ makefield("wrapped", types.Types[TBOOL]),
+ makefield("B", types.Types[TUINT8]),
+ makefield("i", types.Types[TUINT8]),
+ makefield("bucket", types.Types[TUINTPTR]),
+ makefield("checkBucket", types.Types[TUINTPTR]),
+ }
+
+ // build iterator struct holding the above fields
+ hiter := types.New(TSTRUCT)
+ hiter.SetNoalg(true)
+ hiter.SetFields(fields)
+ dowidth(hiter)
+ if hiter.Width != int64(12*Widthptr) {
+ Fatalf("hash_iter size not correct %d %d", hiter.Width, 12*Widthptr)
+ }
+ t.MapType().Hiter = hiter
+ hiter.StructType().Map = t
+ return hiter
+}
+
+// deferstruct makes a runtime._defer structure, with additional space for
+// stksize bytes of args.
+func deferstruct(stksize int64) *types.Type {
+ makefield := func(name string, typ *types.Type) *types.Field {
+ f := types.NewField()
+ f.Type = typ
+ // Unlike the global makefield function, this one needs to set Pkg
+ // because these types might be compared (in SSA CSE sorting).
+ // TODO: unify this makefield and the global one above.
+ f.Sym = &types.Sym{Name: name, Pkg: localpkg}
+ return f
+ }
+ argtype := types.NewArray(types.Types[TUINT8], stksize)
+ argtype.Width = stksize
+ argtype.Align = 1
+ // These fields must match the ones in runtime/runtime2.go:_defer and
+ // cmd/compile/internal/gc/ssa.go:(*state).call.
+ fields := []*types.Field{
+ makefield("siz", types.Types[TUINT32]),
+ makefield("started", types.Types[TBOOL]),
+ makefield("heap", types.Types[TBOOL]),
+ makefield("openDefer", types.Types[TBOOL]),
+ makefield("sp", types.Types[TUINTPTR]),
+ makefield("pc", types.Types[TUINTPTR]),
+ // Note: the types here don't really matter. Defer structures
+ // are always scanned explicitly during stack copying and GC,
+ // so we make them uintptr type even though they are real pointers.
+ makefield("fn", types.Types[TUINTPTR]),
+ makefield("_panic", types.Types[TUINTPTR]),
+ makefield("link", types.Types[TUINTPTR]),
+ makefield("framepc", types.Types[TUINTPTR]),
+ makefield("varp", types.Types[TUINTPTR]),
+ makefield("fd", types.Types[TUINTPTR]),
+ makefield("args", argtype),
+ }
+
+ // build struct holding the above fields
+ s := types.New(TSTRUCT)
+ s.SetNoalg(true)
+ s.SetFields(fields)
+ s.Width = widstruct(s, s, 0, 1)
+ s.Align = uint8(Widthptr)
+ return s
+}
+
+// f is method type, with receiver.
+// return function type, receiver as first argument (or not).
+func methodfunc(f *types.Type, receiver *types.Type) *types.Type {
+ inLen := f.Params().Fields().Len()
+ if receiver != nil {
+ inLen++
+ }
+ in := make([]*Node, 0, inLen)
+
+ if receiver != nil {
+ d := anonfield(receiver)
+ in = append(in, d)
+ }
+
+ for _, t := range f.Params().Fields().Slice() {
+ d := anonfield(t.Type)
+ d.SetIsDDD(t.IsDDD())
+ in = append(in, d)
+ }
+
+ outLen := f.Results().Fields().Len()
+ out := make([]*Node, 0, outLen)
+ for _, t := range f.Results().Fields().Slice() {
+ d := anonfield(t.Type)
+ out = append(out, d)
+ }
+
+ t := functype(nil, in, out)
+ if f.Nname() != nil {
+ // Link to name of original method function.
+ t.SetNname(f.Nname())
+ }
+
+ return t
+}
+
+// methods returns the methods of the non-interface type t, sorted by name.
+// Generates stub functions as needed.
+func methods(t *types.Type) []*Sig {
+ // method type
+ mt := methtype(t)
+
+ if mt == nil {
+ return nil
+ }
+ expandmeth(mt)
+
+ // type stored in interface word
+ it := t
+
+ if !isdirectiface(it) {
+ it = types.NewPtr(t)
+ }
+
+ // make list of methods for t,
+ // generating code if necessary.
+ var ms []*Sig
+ for _, f := range mt.AllMethods().Slice() {
+ if !f.IsMethod() {
+ Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
+ }
+ if f.Type.Recv() == nil {
+ Fatalf("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
+ }
+ if f.Nointerface() {
+ continue
+ }
+
+ method := f.Sym
+ if method == nil {
+ break
+ }
+
+ // get receiver type for this particular method.
+ // if pointer receiver but non-pointer t and
+ // this is not an embedded pointer inside a struct,
+ // method does not apply.
+ if !isMethodApplicable(t, f) {
+ continue
+ }
+
+ sig := &Sig{
+ name: method,
+ isym: methodSym(it, method),
+ tsym: methodSym(t, method),
+ type_: methodfunc(f.Type, t),
+ mtype: methodfunc(f.Type, nil),
+ }
+ ms = append(ms, sig)
+
+ this := f.Type.Recv().Type
+
+ if !sig.isym.Siggen() {
+ sig.isym.SetSiggen(true)
+ if !types.Identical(this, it) {
+ genwrapper(it, f, sig.isym)
+ }
+ }
+
+ if !sig.tsym.Siggen() {
+ sig.tsym.SetSiggen(true)
+ if !types.Identical(this, t) {
+ genwrapper(t, f, sig.tsym)
+ }
+ }
+ }
+
+ return ms
+}
+
+// imethods returns the methods of the interface type t, sorted by name.
+func imethods(t *types.Type) []*Sig {
+ var methods []*Sig
+ for _, f := range t.Fields().Slice() {
+ if f.Type.Etype != TFUNC || f.Sym == nil {
+ continue
+ }
+ if f.Sym.IsBlank() {
+ Fatalf("unexpected blank symbol in interface method set")
+ }
+ if n := len(methods); n > 0 {
+ last := methods[n-1]
+ if !last.name.Less(f.Sym) {
+ Fatalf("sigcmp vs sortinter %v %v", last.name, f.Sym)
+ }
+ }
+
+ sig := &Sig{
+ name: f.Sym,
+ mtype: f.Type,
+ type_: methodfunc(f.Type, nil),
+ }
+ methods = append(methods, sig)
+
+ // NOTE(rsc): Perhaps an oversight that
+ // IfaceType.Method is not in the reflect data.
+ // Generate the method body, so that compiled
+ // code can refer to it.
+ isym := methodSym(t, f.Sym)
+ if !isym.Siggen() {
+ isym.SetSiggen(true)
+ genwrapper(t, f, isym)
+ }
+ }
+
+ return methods
+}
+
+func dimportpath(p *types.Pkg) {
+ if p.Pathsym != nil {
+ return
+ }
+
+ // If we are compiling the runtime package, there are two runtime packages around
+ // -- localpkg and Runtimepkg. We don't want to produce import path symbols for
+ // both of them, so just produce one for localpkg.
+ if myimportpath == "runtime" && p == Runtimepkg {
+ return
+ }
+
+ str := p.Path
+ if p == localpkg {
+ // Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
+ str = myimportpath
+ }
+
+ s := Ctxt.Lookup("type..importpath." + p.Prefix + ".")
+ ot := dnameData(s, 0, str, "", nil, false)
+ ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
+ s.Set(obj.AttrContentAddressable, true)
+ p.Pathsym = s
+}
+
+func dgopkgpath(s *obj.LSym, ot int, pkg *types.Pkg) int {
+ if pkg == nil {
+ return duintptr(s, ot, 0)
+ }
+
+ if pkg == localpkg && myimportpath == "" {
+ // If we don't know the full import path of the package being compiled
+ // (i.e. -p was not passed on the compiler command line), emit a reference to
+ // type..importpath.""., which the linker will rewrite using the correct import path.
+ // Every package that imports this one directly defines the symbol.
+ // See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
+ ns := Ctxt.Lookup(`type..importpath."".`)
+ return dsymptr(s, ot, ns, 0)
+ }
+
+ dimportpath(pkg)
+ return dsymptr(s, ot, pkg.Pathsym, 0)
+}
+
+// dgopkgpathOff writes an offset relocation in s at offset ot to the pkg path symbol.
+func dgopkgpathOff(s *obj.LSym, ot int, pkg *types.Pkg) int {
+ if pkg == nil {
+ return duint32(s, ot, 0)
+ }
+ if pkg == localpkg && myimportpath == "" {
+ // If we don't know the full import path of the package being compiled
+ // (i.e. -p was not passed on the compiler command line), emit a reference to
+ // type..importpath.""., which the linker will rewrite using the correct import path.
+ // Every package that imports this one directly defines the symbol.
+ // See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
+ ns := Ctxt.Lookup(`type..importpath."".`)
+ return dsymptrOff(s, ot, ns)
+ }
+
+ dimportpath(pkg)
+ return dsymptrOff(s, ot, pkg.Pathsym)
+}
+
+// dnameField dumps a reflect.name for a struct field.
+func dnameField(lsym *obj.LSym, ot int, spkg *types.Pkg, ft *types.Field) int {
+ if !types.IsExported(ft.Sym.Name) && ft.Sym.Pkg != spkg {
+ Fatalf("package mismatch for %v", ft.Sym)
+ }
+ nsym := dname(ft.Sym.Name, ft.Note, nil, types.IsExported(ft.Sym.Name))
+ return dsymptr(lsym, ot, nsym, 0)
+}
+
+// dnameData writes the contents of a reflect.name into s at offset ot.
+func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported bool) int {
+ if len(name) > 1<<16-1 {
+ Fatalf("name too long: %s", name)
+ }
+ if len(tag) > 1<<16-1 {
+ Fatalf("tag too long: %s", tag)
+ }
+
+ // Encode name and tag. See reflect/type.go for details.
+ var bits byte
+ l := 1 + 2 + len(name)
+ if exported {
+ bits |= 1 << 0
+ }
+ if len(tag) > 0 {
+ l += 2 + len(tag)
+ bits |= 1 << 1
+ }
+ if pkg != nil {
+ bits |= 1 << 2
+ }
+ b := make([]byte, l)
+ b[0] = bits
+ b[1] = uint8(len(name) >> 8)
+ b[2] = uint8(len(name))
+ copy(b[3:], name)
+ if len(tag) > 0 {
+ tb := b[3+len(name):]
+ tb[0] = uint8(len(tag) >> 8)
+ tb[1] = uint8(len(tag))
+ copy(tb[2:], tag)
+ }
+
+ ot = int(s.WriteBytes(Ctxt, int64(ot), b))
+
+ if pkg != nil {
+ ot = dgopkgpathOff(s, ot, pkg)
+ }
+
+ return ot
+}
+
+var dnameCount int
+
+// dname creates a reflect.name for a struct field or method.
+func dname(name, tag string, pkg *types.Pkg, exported bool) *obj.LSym {
+ // Write out data as "type.." to signal two things to the
+ // linker, first that when dynamically linking, the symbol
+ // should be moved to a relro section, and second that the
+ // contents should not be decoded as a type.
+ sname := "type..namedata."
+ if pkg == nil {
+ // In the common case, share data with other packages.
+ if name == "" {
+ if exported {
+ sname += "-noname-exported." + tag
+ } else {
+ sname += "-noname-unexported." + tag
+ }
+ } else {
+ if exported {
+ sname += name + "." + tag
+ } else {
+ sname += name + "-" + tag
+ }
+ }
+ } else {
+ sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount)
+ dnameCount++
+ }
+ s := Ctxt.Lookup(sname)
+ if len(s.P) > 0 {
+ return s
+ }
+ ot := dnameData(s, 0, name, tag, pkg, exported)
+ ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
+ s.Set(obj.AttrContentAddressable, true)
+ return s
+}
+
+// dextratype dumps the fields of a runtime.uncommontype.
+// dataAdd is the offset in bytes after the header where the
+// backing array of the []method field is written (by dextratypeData).
+func dextratype(lsym *obj.LSym, ot int, t *types.Type, dataAdd int) int {
+ m := methods(t)
+ if t.Sym == nil && len(m) == 0 {
+ return ot
+ }
+ noff := int(Rnd(int64(ot), int64(Widthptr)))
+ if noff != ot {
+ Fatalf("unexpected alignment in dextratype for %v", t)
+ }
+
+ for _, a := range m {
+ dtypesym(a.type_)
+ }
+
+ ot = dgopkgpathOff(lsym, ot, typePkg(t))
+
+ dataAdd += uncommonSize(t)
+ mcount := len(m)
+ if mcount != int(uint16(mcount)) {
+ Fatalf("too many methods on %v: %d", t, mcount)
+ }
+ xcount := sort.Search(mcount, func(i int) bool { return !types.IsExported(m[i].name.Name) })
+ if dataAdd != int(uint32(dataAdd)) {
+ Fatalf("methods are too far away on %v: %d", t, dataAdd)
+ }
+
+ ot = duint16(lsym, ot, uint16(mcount))
+ ot = duint16(lsym, ot, uint16(xcount))
+ ot = duint32(lsym, ot, uint32(dataAdd))
+ ot = duint32(lsym, ot, 0)
+ return ot
+}
+
+func typePkg(t *types.Type) *types.Pkg {
+ tsym := t.Sym
+ if tsym == nil {
+ switch t.Etype {
+ case TARRAY, TSLICE, TPTR, TCHAN:
+ if t.Elem() != nil {
+ tsym = t.Elem().Sym
+ }
+ }
+ }
+ if tsym != nil && t != types.Types[t.Etype] && t != types.Errortype {
+ return tsym.Pkg
+ }
+ return nil
+}
+
+// dextratypeData dumps the backing array for the []method field of
+// runtime.uncommontype.
+func dextratypeData(lsym *obj.LSym, ot int, t *types.Type) int {
+ for _, a := range methods(t) {
+ // ../../../../runtime/type.go:/method
+ exported := types.IsExported(a.name.Name)
+ var pkg *types.Pkg
+ if !exported && a.name.Pkg != typePkg(t) {
+ pkg = a.name.Pkg
+ }
+ nsym := dname(a.name.Name, "", pkg, exported)
+
+ ot = dsymptrOff(lsym, ot, nsym)
+ ot = dmethodptrOff(lsym, ot, dtypesym(a.mtype))
+ ot = dmethodptrOff(lsym, ot, a.isym.Linksym())
+ ot = dmethodptrOff(lsym, ot, a.tsym.Linksym())
+ }
+ return ot
+}
+
+func dmethodptrOff(s *obj.LSym, ot int, x *obj.LSym) int {
+ duint32(s, ot, 0)
+ r := obj.Addrel(s)
+ r.Off = int32(ot)
+ r.Siz = 4
+ r.Sym = x
+ r.Type = objabi.R_METHODOFF
+ return ot + 4
+}
+
+var kinds = []int{
+ TINT: objabi.KindInt,
+ TUINT: objabi.KindUint,
+ TINT8: objabi.KindInt8,
+ TUINT8: objabi.KindUint8,
+ TINT16: objabi.KindInt16,
+ TUINT16: objabi.KindUint16,
+ TINT32: objabi.KindInt32,
+ TUINT32: objabi.KindUint32,
+ TINT64: objabi.KindInt64,
+ TUINT64: objabi.KindUint64,
+ TUINTPTR: objabi.KindUintptr,
+ TFLOAT32: objabi.KindFloat32,
+ TFLOAT64: objabi.KindFloat64,
+ TBOOL: objabi.KindBool,
+ TSTRING: objabi.KindString,
+ TPTR: objabi.KindPtr,
+ TSTRUCT: objabi.KindStruct,
+ TINTER: objabi.KindInterface,
+ TCHAN: objabi.KindChan,
+ TMAP: objabi.KindMap,
+ TARRAY: objabi.KindArray,
+ TSLICE: objabi.KindSlice,
+ TFUNC: objabi.KindFunc,
+ TCOMPLEX64: objabi.KindComplex64,
+ TCOMPLEX128: objabi.KindComplex128,
+ TUNSAFEPTR: objabi.KindUnsafePointer,
+}
+
+// typeptrdata returns the length in bytes of the prefix of t
+// containing pointer data. Anything after this offset is scalar data.
+func typeptrdata(t *types.Type) int64 {
+ if !t.HasPointers() {
+ return 0
+ }
+
+ switch t.Etype {
+ case TPTR,
+ TUNSAFEPTR,
+ TFUNC,
+ TCHAN,
+ TMAP:
+ return int64(Widthptr)
+
+ case TSTRING:
+ // struct { byte *str; intgo len; }
+ return int64(Widthptr)
+
+ case TINTER:
+ // struct { Itab *tab; void *data; } or
+ // struct { Type *type; void *data; }
+ // Note: see comment in plive.go:onebitwalktype1.
+ return 2 * int64(Widthptr)
+
+ case TSLICE:
+ // struct { byte *array; uintgo len; uintgo cap; }
+ return int64(Widthptr)
+
+ case TARRAY:
+ // haspointers already eliminated t.NumElem() == 0.
+ return (t.NumElem()-1)*t.Elem().Width + typeptrdata(t.Elem())
+
+ case TSTRUCT:
+ // Find the last field that has pointers.
+ var lastPtrField *types.Field
+ for _, t1 := range t.Fields().Slice() {
+ if t1.Type.HasPointers() {
+ lastPtrField = t1
+ }
+ }
+ return lastPtrField.Offset + typeptrdata(lastPtrField.Type)
+
+ default:
+ Fatalf("typeptrdata: unexpected type, %v", t)
+ return 0
+ }
+}
+
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+// cmd/compile/internal/gc/reflect.go
+// cmd/link/internal/ld/decodesym.go
+// reflect/type.go
+// runtime/type.go
+const (
+ tflagUncommon = 1 << 0
+ tflagExtraStar = 1 << 1
+ tflagNamed = 1 << 2
+ tflagRegularMemory = 1 << 3
+)
+
+var (
+ memhashvarlen *obj.LSym
+ memequalvarlen *obj.LSym
+)
+
+// dcommontype dumps the contents of a reflect.rtype (runtime._type).
+func dcommontype(lsym *obj.LSym, t *types.Type) int {
+ dowidth(t)
+ eqfunc := geneq(t)
+
+ sptrWeak := true
+ var sptr *obj.LSym
+ if !t.IsPtr() || t.IsPtrElem() {
+ tptr := types.NewPtr(t)
+ if t.Sym != nil || methods(tptr) != nil {
+ sptrWeak = false
+ }
+ sptr = dtypesym(tptr)
+ }
+
+ gcsym, useGCProg, ptrdata := dgcsym(t)
+
+ // ../../../../reflect/type.go:/^type.rtype
+ // actual type structure
+ // type rtype struct {
+ // size uintptr
+ // ptrdata uintptr
+ // hash uint32
+ // tflag tflag
+ // align uint8
+ // fieldAlign uint8
+ // kind uint8
+ // equal func(unsafe.Pointer, unsafe.Pointer) bool
+ // gcdata *byte
+ // str nameOff
+ // ptrToThis typeOff
+ // }
+ ot := 0
+ ot = duintptr(lsym, ot, uint64(t.Width))
+ ot = duintptr(lsym, ot, uint64(ptrdata))
+ ot = duint32(lsym, ot, typehash(t))
+
+ var tflag uint8
+ if uncommonSize(t) != 0 {
+ tflag |= tflagUncommon
+ }
+ if t.Sym != nil && t.Sym.Name != "" {
+ tflag |= tflagNamed
+ }
+ if IsRegularMemory(t) {
+ tflag |= tflagRegularMemory
+ }
+
+ exported := false
+ p := t.LongString()
+ // If we're writing out type T,
+ // we are very likely to write out type *T as well.
+ // Use the string "*T"[1:] for "T", so that the two
+ // share storage. This is a cheap way to reduce the
+ // amount of space taken up by reflect strings.
+ if !strings.HasPrefix(p, "*") {
+ p = "*" + p
+ tflag |= tflagExtraStar
+ if t.Sym != nil {
+ exported = types.IsExported(t.Sym.Name)
+ }
+ } else {
+ if t.Elem() != nil && t.Elem().Sym != nil {
+ exported = types.IsExported(t.Elem().Sym.Name)
+ }
+ }
+
+ ot = duint8(lsym, ot, tflag)
+
+ // runtime (and common sense) expects alignment to be a power of two.
+ i := int(t.Align)
+
+ if i == 0 {
+ i = 1
+ }
+ if i&(i-1) != 0 {
+ Fatalf("invalid alignment %d for %v", t.Align, t)
+ }
+ ot = duint8(lsym, ot, t.Align) // align
+ ot = duint8(lsym, ot, t.Align) // fieldAlign
+
+ i = kinds[t.Etype]
+ if isdirectiface(t) {
+ i |= objabi.KindDirectIface
+ }
+ if useGCProg {
+ i |= objabi.KindGCProg
+ }
+ ot = duint8(lsym, ot, uint8(i)) // kind
+ if eqfunc != nil {
+ ot = dsymptr(lsym, ot, eqfunc, 0) // equality function
+ } else {
+ ot = duintptr(lsym, ot, 0) // type we can't do == with
+ }
+ ot = dsymptr(lsym, ot, gcsym, 0) // gcdata
+
+ nsym := dname(p, "", nil, exported)
+ ot = dsymptrOff(lsym, ot, nsym) // str
+ // ptrToThis
+ if sptr == nil {
+ ot = duint32(lsym, ot, 0)
+ } else if sptrWeak {
+ ot = dsymptrWeakOff(lsym, ot, sptr)
+ } else {
+ ot = dsymptrOff(lsym, ot, sptr)
+ }
+
+ return ot
+}
+
+// typeHasNoAlg reports whether t does not have any associated hash/eq
+// algorithms because t, or some component of t, is marked Noalg.
+func typeHasNoAlg(t *types.Type) bool {
+ a, bad := algtype1(t)
+ return a == ANOEQ && bad.Noalg()
+}
+
+func typesymname(t *types.Type) string {
+ name := t.ShortString()
+ // Use a separate symbol name for Noalg types for #17752.
+ if typeHasNoAlg(t) {
+ name = "noalg." + name
+ }
+ return name
+}
+
+// Fake package for runtime type info (headers)
+// Don't access directly, use typeLookup below.
+var (
+ typepkgmu sync.Mutex // protects typepkg lookups
+ typepkg = types.NewPkg("type", "type")
+)
+
+func typeLookup(name string) *types.Sym {
+ typepkgmu.Lock()
+ s := typepkg.Lookup(name)
+ typepkgmu.Unlock()
+ return s
+}
+
+func typesym(t *types.Type) *types.Sym {
+ return typeLookup(typesymname(t))
+}
+
+// tracksym returns the symbol for tracking use of field/method f, assumed
+// to be a member of struct/interface type t.
+func tracksym(t *types.Type, f *types.Field) *types.Sym {
+ return trackpkg.Lookup(t.ShortString() + "." + f.Sym.Name)
+}
+
+func typesymprefix(prefix string, t *types.Type) *types.Sym {
+ p := prefix + "." + t.ShortString()
+ s := typeLookup(p)
+
+ // This function is for looking up type-related generated functions
+ // (e.g. eq and hash). Make sure they are indeed generated.
+ signatmu.Lock()
+ addsignat(t)
+ signatmu.Unlock()
+
+ //print("algsym: %s -> %+S\n", p, s);
+
+ return s
+}
+
+func typenamesym(t *types.Type) *types.Sym {
+ if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
+ Fatalf("typenamesym %v", t)
+ }
+ s := typesym(t)
+ signatmu.Lock()
+ addsignat(t)
+ signatmu.Unlock()
+ return s
+}
+
+func typename(t *types.Type) *Node {
+ s := typenamesym(t)
+ if s.Def == nil {
+ n := newnamel(src.NoXPos, s)
+ n.Type = types.Types[TUINT8]
+ n.SetClass(PEXTERN)
+ n.SetTypecheck(1)
+ s.Def = asTypesNode(n)
+ }
+
+ n := nod(OADDR, asNode(s.Def), nil)
+ n.Type = types.NewPtr(asNode(s.Def).Type)
+ n.SetTypecheck(1)
+ return n
+}
+
+func itabname(t, itype *types.Type) *Node {
+ if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
+ Fatalf("itabname(%v, %v)", t, itype)
+ }
+ s := itabpkg.Lookup(t.ShortString() + "," + itype.ShortString())
+ if s.Def == nil {
+ n := newname(s)
+ n.Type = types.Types[TUINT8]
+ n.SetClass(PEXTERN)
+ n.SetTypecheck(1)
+ s.Def = asTypesNode(n)
+ itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
+ }
+
+ n := nod(OADDR, asNode(s.Def), nil)
+ n.Type = types.NewPtr(asNode(s.Def).Type)
+ n.SetTypecheck(1)
+ return n
+}
+
+// isreflexive reports whether t has a reflexive equality operator.
+// That is, if x==x for all x of type t.
+func isreflexive(t *types.Type) bool {
+ switch t.Etype {
+ case TBOOL,
+ TINT,
+ TUINT,
+ TINT8,
+ TUINT8,
+ TINT16,
+ TUINT16,
+ TINT32,
+ TUINT32,
+ TINT64,
+ TUINT64,
+ TUINTPTR,
+ TPTR,
+ TUNSAFEPTR,
+ TSTRING,
+ TCHAN:
+ return true
+
+ case TFLOAT32,
+ TFLOAT64,
+ TCOMPLEX64,
+ TCOMPLEX128,
+ TINTER:
+ return false
+
+ case TARRAY:
+ return isreflexive(t.Elem())
+
+ case TSTRUCT:
+ for _, t1 := range t.Fields().Slice() {
+ if !isreflexive(t1.Type) {
+ return false
+ }
+ }
+ return true
+
+ default:
+ Fatalf("bad type for map key: %v", t)
+ return false
+ }
+}
+
+// needkeyupdate reports whether map updates with t as a key
+// need the key to be updated.
+func needkeyupdate(t *types.Type) bool {
+ switch t.Etype {
+ case TBOOL, TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32,
+ TINT64, TUINT64, TUINTPTR, TPTR, TUNSAFEPTR, TCHAN:
+ return false
+
+ case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, // floats and complex can be +0/-0
+ TINTER,
+ TSTRING: // strings might have smaller backing stores
+ return true
+
+ case TARRAY:
+ return needkeyupdate(t.Elem())
+
+ case TSTRUCT:
+ for _, t1 := range t.Fields().Slice() {
+ if needkeyupdate(t1.Type) {
+ return true
+ }
+ }
+ return false
+
+ default:
+ Fatalf("bad type for map key: %v", t)
+ return true
+ }
+}
+
+// hashMightPanic reports whether the hash of a map key of type t might panic.
+func hashMightPanic(t *types.Type) bool {
+ switch t.Etype {
+ case TINTER:
+ return true
+
+ case TARRAY:
+ return hashMightPanic(t.Elem())
+
+ case TSTRUCT:
+ for _, t1 := range t.Fields().Slice() {
+ if hashMightPanic(t1.Type) {
+ return true
+ }
+ }
+ return false
+
+ default:
+ return false
+ }
+}
+
+// formalType replaces byte and rune aliases with real types.
+// They've been separate internally to make error messages
+// better, but we have to merge them in the reflect tables.
+func formalType(t *types.Type) *types.Type {
+ if t == types.Bytetype || t == types.Runetype {
+ return types.Types[t.Etype]
+ }
+ return t
+}
+
+func dtypesym(t *types.Type) *obj.LSym {
+ t = formalType(t)
+ if t.IsUntyped() {
+ Fatalf("dtypesym %v", t)
+ }
+
+ s := typesym(t)
+ lsym := s.Linksym()
+ if s.Siggen() {
+ return lsym
+ }
+ s.SetSiggen(true)
+
+ // special case (look for runtime below):
+ // when compiling package runtime,
+ // emit the type structures for int, float, etc.
+ tbase := t
+
+ if t.IsPtr() && t.Sym == nil && t.Elem().Sym != nil {
+ tbase = t.Elem()
+ }
+ dupok := 0
+ if tbase.Sym == nil {
+ dupok = obj.DUPOK
+ }
+
+ if myimportpath != "runtime" || (tbase != types.Types[tbase.Etype] && tbase != types.Bytetype && tbase != types.Runetype && tbase != types.Errortype) { // int, float, etc
+ // named types from other files are defined only by those files
+ if tbase.Sym != nil && tbase.Sym.Pkg != localpkg {
+ if i, ok := typeSymIdx[tbase]; ok {
+ lsym.Pkg = tbase.Sym.Pkg.Prefix
+ if t != tbase {
+ lsym.SymIdx = int32(i[1])
+ } else {
+ lsym.SymIdx = int32(i[0])
+ }
+ lsym.Set(obj.AttrIndexed, true)
+ }
+ return lsym
+ }
+ // TODO(mdempsky): Investigate whether this can happen.
+ if tbase.Etype == TFORW {
+ return lsym
+ }
+ }
+
+ ot := 0
+ switch t.Etype {
+ default:
+ ot = dcommontype(lsym, t)
+ ot = dextratype(lsym, ot, t, 0)
+
+ case TARRAY:
+ // ../../../../runtime/type.go:/arrayType
+ s1 := dtypesym(t.Elem())
+ t2 := types.NewSlice(t.Elem())
+ s2 := dtypesym(t2)
+ ot = dcommontype(lsym, t)
+ ot = dsymptr(lsym, ot, s1, 0)
+ ot = dsymptr(lsym, ot, s2, 0)
+ ot = duintptr(lsym, ot, uint64(t.NumElem()))
+ ot = dextratype(lsym, ot, t, 0)
+
+ case TSLICE:
+ // ../../../../runtime/type.go:/sliceType
+ s1 := dtypesym(t.Elem())
+ ot = dcommontype(lsym, t)
+ ot = dsymptr(lsym, ot, s1, 0)
+ ot = dextratype(lsym, ot, t, 0)
+
+ case TCHAN:
+ // ../../../../runtime/type.go:/chanType
+ s1 := dtypesym(t.Elem())
+ ot = dcommontype(lsym, t)
+ ot = dsymptr(lsym, ot, s1, 0)
+ ot = duintptr(lsym, ot, uint64(t.ChanDir()))
+ ot = dextratype(lsym, ot, t, 0)
+
+ case TFUNC:
+ for _, t1 := range t.Recvs().Fields().Slice() {
+ dtypesym(t1.Type)
+ }
+ isddd := false
+ for _, t1 := range t.Params().Fields().Slice() {
+ isddd = t1.IsDDD()
+ dtypesym(t1.Type)
+ }
+ for _, t1 := range t.Results().Fields().Slice() {
+ dtypesym(t1.Type)
+ }
+
+ ot = dcommontype(lsym, t)
+ inCount := t.NumRecvs() + t.NumParams()
+ outCount := t.NumResults()
+ if isddd {
+ outCount |= 1 << 15
+ }
+ ot = duint16(lsym, ot, uint16(inCount))
+ ot = duint16(lsym, ot, uint16(outCount))
+ if Widthptr == 8 {
+ ot += 4 // align for *rtype
+ }
+
+ dataAdd := (inCount + t.NumResults()) * Widthptr
+ ot = dextratype(lsym, ot, t, dataAdd)
+
+ // Array of rtype pointers follows funcType.
+ for _, t1 := range t.Recvs().Fields().Slice() {
+ ot = dsymptr(lsym, ot, dtypesym(t1.Type), 0)
+ }
+ for _, t1 := range t.Params().Fields().Slice() {
+ ot = dsymptr(lsym, ot, dtypesym(t1.Type), 0)
+ }
+ for _, t1 := range t.Results().Fields().Slice() {
+ ot = dsymptr(lsym, ot, dtypesym(t1.Type), 0)
+ }
+
+ case TINTER:
+ m := imethods(t)
+ n := len(m)
+ for _, a := range m {
+ dtypesym(a.type_)
+ }
+
+ // ../../../../runtime/type.go:/interfaceType
+ ot = dcommontype(lsym, t)
+
+ var tpkg *types.Pkg
+ if t.Sym != nil && t != types.Types[t.Etype] && t != types.Errortype {
+ tpkg = t.Sym.Pkg
+ }
+ ot = dgopkgpath(lsym, ot, tpkg)
+
+ ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
+ ot = duintptr(lsym, ot, uint64(n))
+ ot = duintptr(lsym, ot, uint64(n))
+ dataAdd := imethodSize() * n
+ ot = dextratype(lsym, ot, t, dataAdd)
+
+ for _, a := range m {
+ // ../../../../runtime/type.go:/imethod
+ exported := types.IsExported(a.name.Name)
+ var pkg *types.Pkg
+ if !exported && a.name.Pkg != tpkg {
+ pkg = a.name.Pkg
+ }
+ nsym := dname(a.name.Name, "", pkg, exported)
+
+ ot = dsymptrOff(lsym, ot, nsym)
+ ot = dsymptrOff(lsym, ot, dtypesym(a.type_))
+ }
+
+ // ../../../../runtime/type.go:/mapType
+ case TMAP:
+ s1 := dtypesym(t.Key())
+ s2 := dtypesym(t.Elem())
+ s3 := dtypesym(bmap(t))
+ hasher := genhash(t.Key())
+
+ ot = dcommontype(lsym, t)
+ ot = dsymptr(lsym, ot, s1, 0)
+ ot = dsymptr(lsym, ot, s2, 0)
+ ot = dsymptr(lsym, ot, s3, 0)
+ ot = dsymptr(lsym, ot, hasher, 0)
+ var flags uint32
+ // Note: flags must match maptype accessors in ../../../../runtime/type.go
+ // and maptype builder in ../../../../reflect/type.go:MapOf.
+ if t.Key().Width > MAXKEYSIZE {
+ ot = duint8(lsym, ot, uint8(Widthptr))
+ flags |= 1 // indirect key
+ } else {
+ ot = duint8(lsym, ot, uint8(t.Key().Width))
+ }
+
+ if t.Elem().Width > MAXELEMSIZE {
+ ot = duint8(lsym, ot, uint8(Widthptr))
+ flags |= 2 // indirect value
+ } else {
+ ot = duint8(lsym, ot, uint8(t.Elem().Width))
+ }
+ ot = duint16(lsym, ot, uint16(bmap(t).Width))
+ if isreflexive(t.Key()) {
+ flags |= 4 // reflexive key
+ }
+ if needkeyupdate(t.Key()) {
+ flags |= 8 // need key update
+ }
+ if hashMightPanic(t.Key()) {
+ flags |= 16 // hash might panic
+ }
+ ot = duint32(lsym, ot, flags)
+ ot = dextratype(lsym, ot, t, 0)
+
+ case TPTR:
+ if t.Elem().Etype == TANY {
+ // ../../../../runtime/type.go:/UnsafePointerType
+ ot = dcommontype(lsym, t)
+ ot = dextratype(lsym, ot, t, 0)
+
+ break
+ }
+
+ // ../../../../runtime/type.go:/ptrType
+ s1 := dtypesym(t.Elem())
+
+ ot = dcommontype(lsym, t)
+ ot = dsymptr(lsym, ot, s1, 0)
+ ot = dextratype(lsym, ot, t, 0)
+
+ // ../../../../runtime/type.go:/structType
+ // for security, only the exported fields.
+ case TSTRUCT:
+ fields := t.Fields().Slice()
+ for _, t1 := range fields {
+ dtypesym(t1.Type)
+ }
+
+ // All non-exported struct field names within a struct
+ // type must originate from a single package. By
+ // identifying and recording that package within the
+ // struct type descriptor, we can omit that
+ // information from the field descriptors.
+ var spkg *types.Pkg
+ for _, f := range fields {
+ if !types.IsExported(f.Sym.Name) {
+ spkg = f.Sym.Pkg
+ break
+ }
+ }
+
+ ot = dcommontype(lsym, t)
+ ot = dgopkgpath(lsym, ot, spkg)
+ ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
+ ot = duintptr(lsym, ot, uint64(len(fields)))
+ ot = duintptr(lsym, ot, uint64(len(fields)))
+
+ dataAdd := len(fields) * structfieldSize()
+ ot = dextratype(lsym, ot, t, dataAdd)
+
+ for _, f := range fields {
+ // ../../../../runtime/type.go:/structField
+ ot = dnameField(lsym, ot, spkg, f)
+ ot = dsymptr(lsym, ot, dtypesym(f.Type), 0)
+ offsetAnon := uint64(f.Offset) << 1
+ if offsetAnon>>1 != uint64(f.Offset) {
+ Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
+ }
+ if f.Embedded != 0 {
+ offsetAnon |= 1
+ }
+ ot = duintptr(lsym, ot, offsetAnon)
+ }
+ }
+
+ ot = dextratypeData(lsym, ot, t)
+ ggloblsym(lsym, int32(ot), int16(dupok|obj.RODATA))
+
+ // The linker will leave a table of all the typelinks for
+ // types in the binary, so the runtime can find them.
+ //
+ // When buildmode=shared, all types are in typelinks so the
+ // runtime can deduplicate type pointers.
+ keep := Ctxt.Flag_dynlink
+ if !keep && t.Sym == nil {
+ // For an unnamed type, we only need the link if the type can
+ // be created at run time by reflect.PtrTo and similar
+ // functions. If the type exists in the program, those
+ // functions must return the existing type structure rather
+ // than creating a new one.
+ switch t.Etype {
+ case TPTR, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT:
+ keep = true
+ }
+ }
+ // Do not put Noalg types in typelinks. See issue #22605.
+ if typeHasNoAlg(t) {
+ keep = false
+ }
+ lsym.Set(obj.AttrMakeTypelink, keep)
+
+ return lsym
+}
+
+// ifaceMethodOffset returns the offset of the i-th method in the interface
+// type descriptor, ityp.
+func ifaceMethodOffset(ityp *types.Type, i int64) int64 {
+ // interface type descriptor layout is struct {
+ // _type // commonSize
+ // pkgpath // 1 word
+ // []imethod // 3 words (pointing to [...]imethod below)
+ // uncommontype // uncommonSize
+ // [...]imethod
+ // }
+ // The size of imethod is 8.
+ return int64(commonSize()+4*Widthptr+uncommonSize(ityp)) + i*8
+}
+
+// for each itabEntry, gather the methods on
+// the concrete type that implement the interface
+func peekitabs() {
+ for i := range itabs {
+ tab := &itabs[i]
+ methods := genfun(tab.t, tab.itype)
+ if len(methods) == 0 {
+ continue
+ }
+ tab.entries = methods
+ }
+}
+
+// for the given concrete type and interface
+// type, return the (sorted) set of methods
+// on the concrete type that implement the interface
+func genfun(t, it *types.Type) []*obj.LSym {
+ if t == nil || it == nil {
+ return nil
+ }
+ sigs := imethods(it)
+ methods := methods(t)
+ out := make([]*obj.LSym, 0, len(sigs))
+ // TODO(mdempsky): Short circuit before calling methods(t)?
+ // See discussion on CL 105039.
+ if len(sigs) == 0 {
+ return nil
+ }
+
+ // both sigs and methods are sorted by name,
+ // so we can find the intersect in a single pass
+ for _, m := range methods {
+ if m.name == sigs[0].name {
+ out = append(out, m.isym.Linksym())
+ sigs = sigs[1:]
+ if len(sigs) == 0 {
+ break
+ }
+ }
+ }
+
+ if len(sigs) != 0 {
+ Fatalf("incomplete itab")
+ }
+
+ return out
+}
+
+// itabsym uses the information gathered in
+// peekitabs to de-virtualize interface methods.
+// Since this is called by the SSA backend, it shouldn't
+// generate additional Nodes, Syms, etc.
+func itabsym(it *obj.LSym, offset int64) *obj.LSym {
+ var syms []*obj.LSym
+ if it == nil {
+ return nil
+ }
+
+ for i := range itabs {
+ e := &itabs[i]
+ if e.lsym == it {
+ syms = e.entries
+ break
+ }
+ }
+ if syms == nil {
+ return nil
+ }
+
+ // keep this arithmetic in sync with *itab layout
+ methodnum := int((offset - 2*int64(Widthptr) - 8) / int64(Widthptr))
+ if methodnum >= len(syms) {
+ return nil
+ }
+ return syms[methodnum]
+}
+
+// addsignat ensures that a runtime type descriptor is emitted for t.
+func addsignat(t *types.Type) {
+ if _, ok := signatset[t]; !ok {
+ signatset[t] = struct{}{}
+ signatslice = append(signatslice, t)
+ }
+}
+
+func addsignats(dcls []*Node) {
+ // copy types from dcl list to signatset
+ for _, n := range dcls {
+ if n.Op == OTYPE {
+ addsignat(n.Type)
+ }
+ }
+}
+
+func dumpsignats() {
+ // Process signatset. Use a loop, as dtypesym adds
+ // entries to signatset while it is being processed.
+ signats := make([]typeAndStr, len(signatslice))
+ for len(signatslice) > 0 {
+ signats = signats[:0]
+ // Transfer entries to a slice and sort, for reproducible builds.
+ for _, t := range signatslice {
+ signats = append(signats, typeAndStr{t: t, short: typesymname(t), regular: t.String()})
+ delete(signatset, t)
+ }
+ signatslice = signatslice[:0]
+ sort.Sort(typesByString(signats))
+ for _, ts := range signats {
+ t := ts.t
+ dtypesym(t)
+ if t.Sym != nil {
+ dtypesym(types.NewPtr(t))
+ }
+ }
+ }
+}
+
+func dumptabs() {
+ // process itabs
+ for _, i := range itabs {
+ // dump empty itab symbol into i.sym
+ // type itab struct {
+ // inter *interfacetype
+ // _type *_type
+ // hash uint32
+ // _ [4]byte
+ // fun [1]uintptr // variable sized
+ // }
+ o := dsymptr(i.lsym, 0, dtypesym(i.itype), 0)
+ o = dsymptr(i.lsym, o, dtypesym(i.t), 0)
+ o = duint32(i.lsym, o, typehash(i.t)) // copy of type hash
+ o += 4 // skip unused field
+ for _, fn := range genfun(i.t, i.itype) {
+ o = dsymptr(i.lsym, o, fn, 0) // method pointer for each method
+ }
+ // Nothing writes static itabs, so they are read only.
+ ggloblsym(i.lsym, int32(o), int16(obj.DUPOK|obj.RODATA))
+ i.lsym.Set(obj.AttrContentAddressable, true)
+ }
+
+ // process ptabs
+ if localpkg.Name == "main" && len(ptabs) > 0 {
+ ot := 0
+ s := Ctxt.Lookup("go.plugin.tabs")
+ 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)
+ tsym := dtypesym(p.t)
+ ot = dsymptrOff(s, ot, nsym)
+ ot = dsymptrOff(s, ot, tsym)
+ // Plugin exports symbols as interfaces. Mark their types
+ // as UsedInIface.
+ tsym.Set(obj.AttrUsedInIface, true)
+ }
+ ggloblsym(s, int32(ot), int16(obj.RODATA))
+
+ ot = 0
+ s = Ctxt.Lookup("go.plugin.exports")
+ for _, p := range ptabs {
+ ot = dsymptr(s, ot, p.s.Linksym(), 0)
+ }
+ ggloblsym(s, int32(ot), int16(obj.RODATA))
+ }
+}
+
+func dumpimportstrings() {
+ // generate import strings for imported packages
+ for _, p := range types.ImportedPkgList() {
+ dimportpath(p)
+ }
+}
+
+func dumpbasictypes() {
+ // do basic types if compiling package runtime.
+ // they have to be in at least one package,
+ // and runtime is always loaded implicitly,
+ // so this is as good as any.
+ // another possible choice would be package main,
+ // but using runtime means fewer copies in object files.
+ if myimportpath == "runtime" {
+ for i := types.EType(1); i <= TBOOL; i++ {
+ dtypesym(types.NewPtr(types.Types[i]))
+ }
+ dtypesym(types.NewPtr(types.Types[TSTRING]))
+ dtypesym(types.NewPtr(types.Types[TUNSAFEPTR]))
+
+ // emit type structs for error and func(error) string.
+ // The latter is the type of an auto-generated wrapper.
+ dtypesym(types.NewPtr(types.Errortype))
+
+ dtypesym(functype(nil, []*Node{anonfield(types.Errortype)}, []*Node{anonfield(types.Types[TSTRING])}))
+
+ // add paths for runtime and main, which 6l imports implicitly.
+ dimportpath(Runtimepkg)
+
+ if flag_race {
+ dimportpath(racepkg)
+ }
+ if flag_msan {
+ dimportpath(msanpkg)
+ }
+ dimportpath(types.NewPkg("main", ""))
+ }
+}
+
+type typeAndStr struct {
+ t *types.Type
+ short string
+ regular string
+}
+
+type typesByString []typeAndStr
+
+func (a typesByString) Len() int { return len(a) }
+func (a typesByString) Less(i, j int) bool {
+ if a[i].short != a[j].short {
+ return a[i].short < a[j].short
+ }
+ // When the only difference between the types is whether
+ // they refer to byte or uint8, such as **byte vs **uint8,
+ // the types' ShortStrings can be identical.
+ // To preserve deterministic sort ordering, sort these by String().
+ if a[i].regular != a[j].regular {
+ return a[i].regular < a[j].regular
+ }
+ // Identical anonymous interfaces defined in different locations
+ // will be equal for the above checks, but different in DWARF output.
+ // Sort by source position to ensure deterministic order.
+ // See issues 27013 and 30202.
+ if a[i].t.Etype == types.TINTER && a[i].t.Methods().Len() > 0 {
+ return a[i].t.Methods().Index(0).Pos.Before(a[j].t.Methods().Index(0).Pos)
+ }
+ return false
+}
+func (a typesByString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+
+// maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap,
+// which holds 1-bit entries describing where pointers are in a given type.
+// Above this length, the GC information is recorded as a GC program,
+// which can express repetition compactly. In either form, the
+// information is used by the runtime to initialize the heap bitmap,
+// and for large types (like 128 or more words), they are roughly the
+// same speed. GC programs are never much larger and often more
+// compact. (If large arrays are involved, they can be arbitrarily
+// more compact.)
+//
+// The cutoff must be large enough that any allocation large enough to
+// use a GC program is large enough that it does not share heap bitmap
+// bytes with any other objects, allowing the GC program execution to
+// assume an aligned start and not use atomic operations. In the current
+// runtime, this means all malloc size classes larger than the cutoff must
+// be multiples of four words. On 32-bit systems that's 16 bytes, and
+// all size classes >= 16 bytes are 16-byte aligned, so no real constraint.
+// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed
+// for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated
+// is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes
+// must be >= 4.
+//
+// We used to use 16 because the GC programs do have some constant overhead
+// to get started, and processing 128 pointers seems to be enough to
+// amortize that overhead well.
+//
+// To make sure that the runtime's chansend can call typeBitsBulkBarrier,
+// we raised the limit to 2048, so that even 32-bit systems are guaranteed to
+// use bitmaps for objects up to 64 kB in size.
+//
+// Also known to reflect/type.go.
+//
+const maxPtrmaskBytes = 2048
+
+// dgcsym emits and returns a data symbol containing GC information for type t,
+// along with a boolean reporting whether the UseGCProg bit should be set in
+// the type kind, and the ptrdata field to record in the reflect type information.
+func dgcsym(t *types.Type) (lsym *obj.LSym, useGCProg bool, ptrdata int64) {
+ ptrdata = typeptrdata(t)
+ if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 {
+ lsym = dgcptrmask(t)
+ return
+ }
+
+ useGCProg = true
+ lsym, ptrdata = dgcprog(t)
+ return
+}
+
+// dgcptrmask emits and returns the symbol containing a pointer mask for type t.
+func dgcptrmask(t *types.Type) *obj.LSym {
+ ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8)
+ fillptrmask(t, ptrmask)
+ p := fmt.Sprintf("gcbits.%x", ptrmask)
+
+ sym := Runtimepkg.Lookup(p)
+ lsym := sym.Linksym()
+ if !sym.Uniq() {
+ sym.SetUniq(true)
+ for i, x := range ptrmask {
+ duint8(lsym, i, x)
+ }
+ ggloblsym(lsym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ lsym.Set(obj.AttrContentAddressable, true)
+ }
+ return lsym
+}
+
+// fillptrmask fills in ptrmask with 1s corresponding to the
+// word offsets in t that hold pointers.
+// ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits.
+func fillptrmask(t *types.Type, ptrmask []byte) {
+ for i := range ptrmask {
+ ptrmask[i] = 0
+ }
+ if !t.HasPointers() {
+ return
+ }
+
+ vec := bvalloc(8 * int32(len(ptrmask)))
+ onebitwalktype1(t, 0, vec)
+
+ nptr := typeptrdata(t) / int64(Widthptr)
+ for i := int64(0); i < nptr; i++ {
+ if vec.Get(int32(i)) {
+ ptrmask[i/8] |= 1 << (uint(i) % 8)
+ }
+ }
+}
+
+// dgcprog emits and returns the symbol containing a GC program for type t
+// along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]).
+// In practice, the size is typeptrdata(t) except for non-trivial arrays.
+// For non-trivial arrays, the program describes the full t.Width size.
+func dgcprog(t *types.Type) (*obj.LSym, int64) {
+ dowidth(t)
+ if t.Width == BADWIDTH {
+ Fatalf("dgcprog: %v badwidth", t)
+ }
+ lsym := typesymprefix(".gcprog", t).Linksym()
+ var p GCProg
+ p.init(lsym)
+ p.emit(t, 0)
+ offset := p.w.BitIndex() * int64(Widthptr)
+ p.end()
+ if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width {
+ Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width)
+ }
+ return lsym, offset
+}
+
+type GCProg struct {
+ lsym *obj.LSym
+ symoff int
+ w gcprog.Writer
+}
+
+var Debug_gcprog int // set by -d gcprog
+
+func (p *GCProg) init(lsym *obj.LSym) {
+ p.lsym = lsym
+ p.symoff = 4 // first 4 bytes hold program length
+ p.w.Init(p.writeByte)
+ if Debug_gcprog > 0 {
+ fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", lsym)
+ p.w.Debug(os.Stderr)
+ }
+}
+
+func (p *GCProg) writeByte(x byte) {
+ p.symoff = duint8(p.lsym, p.symoff, x)
+}
+
+func (p *GCProg) end() {
+ p.w.End()
+ duint32(p.lsym, 0, uint32(p.symoff-4))
+ ggloblsym(p.lsym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ if Debug_gcprog > 0 {
+ fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.lsym)
+ }
+}
+
+func (p *GCProg) emit(t *types.Type, offset int64) {
+ dowidth(t)
+ if !t.HasPointers() {
+ return
+ }
+ if t.Width == int64(Widthptr) {
+ p.w.Ptr(offset / int64(Widthptr))
+ return
+ }
+ switch t.Etype {
+ default:
+ Fatalf("GCProg.emit: unexpected type %v", t)
+
+ case TSTRING:
+ p.w.Ptr(offset / int64(Widthptr))
+
+ case TINTER:
+ // Note: the first word isn't a pointer. See comment in plive.go:onebitwalktype1.
+ p.w.Ptr(offset/int64(Widthptr) + 1)
+
+ case TSLICE:
+ p.w.Ptr(offset / int64(Widthptr))
+
+ case TARRAY:
+ if t.NumElem() == 0 {
+ // should have been handled by haspointers check above
+ Fatalf("GCProg.emit: empty array")
+ }
+
+ // Flatten array-of-array-of-array to just a big array by multiplying counts.
+ count := t.NumElem()
+ elem := t.Elem()
+ for elem.IsArray() {
+ count *= elem.NumElem()
+ elem = elem.Elem()
+ }
+
+ if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) {
+ // Cheaper to just emit the bits.
+ for i := int64(0); i < count; i++ {
+ p.emit(elem, offset+i*elem.Width)
+ }
+ return
+ }
+ p.emit(elem, offset)
+ p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr))
+ p.w.Repeat(elem.Width/int64(Widthptr), count-1)
+
+ case TSTRUCT:
+ for _, t1 := range t.Fields().Slice() {
+ p.emit(t1.Type, offset+t1.Offset)
+ }
+ }
+}
+
+// zeroaddr returns the address of a symbol with at least
+// size bytes of zeros.
+func zeroaddr(size int64) *Node {
+ if size >= 1<<31 {
+ Fatalf("map elem too big %d", size)
+ }
+ if zerosize < size {
+ zerosize = size
+ }
+ s := mappkg.Lookup("zero")
+ if s.Def == nil {
+ x := newname(s)
+ x.Type = types.Types[TUINT8]
+ x.SetClass(PEXTERN)
+ x.SetTypecheck(1)
+ s.Def = asTypesNode(x)
+ }
+ z := nod(OADDR, asNode(s.Def), nil)
+ z.Type = types.NewPtr(types.Types[TUINT8])
+ z.SetTypecheck(1)
+ return z
+}
diff --git a/src/cmd/compile/internal/gc/reproduciblebuilds_test.go b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go
new file mode 100644
index 0000000..8101e44
--- /dev/null
+++ b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go
@@ -0,0 +1,112 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc_test
+
+import (
+ "bytes"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+)
+
+func TestReproducibleBuilds(t *testing.T) {
+ tests := []string{
+ "issue20272.go",
+ "issue27013.go",
+ "issue30202.go",
+ }
+
+ testenv.MustHaveGoBuild(t)
+ iters := 10
+ if testing.Short() {
+ iters = 4
+ }
+ t.Parallel()
+ for _, test := range tests {
+ test := test
+ t.Run(test, func(t *testing.T) {
+ t.Parallel()
+ var want []byte
+ tmp, err := ioutil.TempFile("", "")
+ if err != nil {
+ t.Fatalf("temp file creation failed: %v", err)
+ }
+ defer os.Remove(tmp.Name())
+ defer tmp.Close()
+ for i := 0; i < iters; i++ {
+ // Note: use -c 2 to expose any nondeterminism which is the result
+ // of the runtime scheduler.
+ out, err := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-c", "2", "-o", tmp.Name(), filepath.Join("testdata", "reproducible", test)).CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to compile: %v\n%s", err, out)
+ }
+ obj, err := ioutil.ReadFile(tmp.Name())
+ if err != nil {
+ t.Fatalf("failed to read object file: %v", err)
+ }
+ if i == 0 {
+ want = obj
+ } else {
+ if !bytes.Equal(want, obj) {
+ t.Fatalf("builds produced different output after %d iters (%d bytes vs %d bytes)", i, len(want), len(obj))
+ }
+ }
+ }
+ })
+ }
+}
+
+func TestIssue38068(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ t.Parallel()
+
+ // Compile a small package with and without the concurrent
+ // backend, then check to make sure that the resulting archives
+ // are identical. Note: this uses "go tool compile" instead of
+ // "go build" since the latter will generate differnent build IDs
+ // if it sees different command line flags.
+ scenarios := []struct {
+ tag string
+ args string
+ libpath string
+ }{
+ {tag: "serial", args: "-c=1"},
+ {tag: "concurrent", args: "-c=2"}}
+
+ tmpdir, err := ioutil.TempDir("", "TestIssue38068")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ src := filepath.Join("testdata", "reproducible", "issue38068.go")
+ for i := range scenarios {
+ s := &scenarios[i]
+ s.libpath = filepath.Join(tmpdir, s.tag+".a")
+ // Note: use of "-p" required in order for DWARF to be generated.
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-trimpath", "-p=issue38068", "-buildid=", s.args, "-o", s.libpath, src)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
+ }
+ }
+
+ readBytes := func(fn string) []byte {
+ payload, err := ioutil.ReadFile(fn)
+ if err != nil {
+ t.Fatalf("failed to read executable '%s': %v", fn, err)
+ }
+ return payload
+ }
+
+ b1 := readBytes(scenarios[0].libpath)
+ b2 := readBytes(scenarios[1].libpath)
+ if !bytes.Equal(b1, b2) {
+ t.Fatalf("concurrent and serial builds produced different output")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/scc.go b/src/cmd/compile/internal/gc/scc.go
new file mode 100644
index 0000000..5c7935a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/scc.go
@@ -0,0 +1,140 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+// Strongly connected components.
+//
+// Run analysis on minimal sets of mutually recursive functions
+// or single non-recursive functions, bottom up.
+//
+// Finding these sets is finding strongly connected components
+// 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.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.
+//
+// Second, each function becomes two virtual nodes in the graph,
+// with numbers n and n+1. We record the function's node number as n
+// but search from node n+1. If the search tells us that the component
+// number (min) is n+1, we know that this is a trivial component: one function
+// plus its closures. If the search tells us that the component number is
+// n, then there was a path from node n+1 back to node n, meaning that
+// the function set is mutually recursive. The escape analysis can be
+// more precise when analyzing a single non-recursive function than
+// when analyzing a set of mutually recursive functions.
+
+type bottomUpVisitor struct {
+ analyze func([]*Node, bool)
+ visitgen uint32
+ nodeID map[*Node]uint32
+ stack []*Node
+}
+
+// visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list.
+// It calls analyze with successive groups of functions, working from
+// the bottom of the call graph upward. Each time analyze is called with
+// a list of functions, every function on that list only calls other functions
+// on the list or functions that have been passed in previous invocations of
+// analyze. Closures appear in the same list as their outer functions.
+// The lists are as short as possible while preserving those requirements.
+// (In a typical program, many invocations of analyze will be passed just
+// a single function.) The boolean argument 'recursive' passed to analyze
+// specifies whether the functions on the list are mutually recursive.
+// If recursive is false, the list consists of only a single function and its closures.
+// If recursive is true, the list may still contain only a single function,
+// if that function is itself recursive.
+func visitBottomUp(list []*Node, analyze func(list []*Node, recursive bool)) {
+ var v bottomUpVisitor
+ v.analyze = analyze
+ v.nodeID = make(map[*Node]uint32)
+ for _, n := range list {
+ if n.Op == ODCLFUNC && !n.Func.IsHiddenClosure() {
+ v.visit(n)
+ }
+ }
+}
+
+func (v *bottomUpVisitor) visit(n *Node) uint32 {
+ if id := v.nodeID[n]; id > 0 {
+ // already visited
+ return id
+ }
+
+ v.visitgen++
+ id := v.visitgen
+ v.nodeID[n] = id
+ v.visitgen++
+ min := v.visitgen
+ v.stack = append(v.stack, n)
+
+ inspectList(n.Nbody, func(n *Node) bool {
+ switch n.Op {
+ case ONAME:
+ if n.Class() == PFUNC {
+ if n.isMethodExpression() {
+ n = asNode(n.Type.Nname())
+ }
+ if n != nil && n.Name.Defn != nil {
+ if m := v.visit(n.Name.Defn); m < min {
+ min = m
+ }
+ }
+ }
+ case ODOTMETH:
+ fn := asNode(n.Type.Nname())
+ if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
+ if m := v.visit(fn.Name.Defn); m < min {
+ min = m
+ }
+ }
+ case OCALLPART:
+ fn := asNode(callpartMethod(n).Type.Nname())
+ if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
+ if m := v.visit(fn.Name.Defn); m < min {
+ min = m
+ }
+ }
+ case OCLOSURE:
+ if m := v.visit(n.Func.Closure); m < min {
+ min = m
+ }
+ }
+ return true
+ })
+
+ if (min == id || min == id+1) && !n.Func.IsHiddenClosure() {
+ // This node is the root of a strongly connected component.
+
+ // The original min passed to visitcodelist was v.nodeID[n]+1.
+ // 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
+
+ // Remove connected component from stack.
+ // Mark walkgen so that future visits return a large number
+ // so as not to affect the caller's min.
+
+ var i int
+ for i = len(v.stack) - 1; i >= 0; i-- {
+ x := v.stack[i]
+ if x == n {
+ break
+ }
+ v.nodeID[x] = ^uint32(0)
+ }
+ v.nodeID[n] = ^uint32(0)
+ block := v.stack[i:]
+ // Run escape analysis on this set of functions.
+ v.stack = v.stack[:i]
+ v.analyze(block, recursive)
+ }
+
+ return min
+}
diff --git a/src/cmd/compile/internal/gc/scope.go b/src/cmd/compile/internal/gc/scope.go
new file mode 100644
index 0000000..e66b859
--- /dev/null
+++ b/src/cmd/compile/internal/gc/scope.go
@@ -0,0 +1,109 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/internal/dwarf"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+ "sort"
+)
+
+// See golang.org/issue/20390.
+func xposBefore(p, q src.XPos) bool {
+ return Ctxt.PosTable.Pos(p).Before(Ctxt.PosTable.Pos(q))
+}
+
+func findScope(marks []Mark, pos src.XPos) ScopeID {
+ i := sort.Search(len(marks), func(i int) bool {
+ return xposBefore(pos, marks[i].Pos)
+ })
+ if i == 0 {
+ return 0
+ }
+ return marks[i-1].Scope
+}
+
+func assembleScopes(fnsym *obj.LSym, fn *Node, dwarfVars []*dwarf.Var, varScopes []ScopeID) []dwarf.Scope {
+ // Initialize the DWARF scope tree based on lexical scopes.
+ dwarfScopes := make([]dwarf.Scope, 1+len(fn.Func.Parents))
+ for i, parent := range fn.Func.Parents {
+ dwarfScopes[i+1].Parent = int32(parent)
+ }
+
+ scopeVariables(dwarfVars, varScopes, dwarfScopes)
+ scopePCs(fnsym, fn.Func.Marks, dwarfScopes)
+ return compactScopes(dwarfScopes)
+}
+
+// scopeVariables assigns DWARF variable records to their scopes.
+func scopeVariables(dwarfVars []*dwarf.Var, varScopes []ScopeID, dwarfScopes []dwarf.Scope) {
+ sort.Stable(varsByScopeAndOffset{dwarfVars, varScopes})
+
+ i0 := 0
+ for i := range dwarfVars {
+ if varScopes[i] == varScopes[i0] {
+ continue
+ }
+ dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:i]
+ i0 = i
+ }
+ if i0 < len(dwarfVars) {
+ dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:]
+ }
+}
+
+// scopePCs assigns PC ranges to their scopes.
+func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) {
+ // If there aren't any child scopes (in particular, when scope
+ // tracking is disabled), we can skip a whole lot of work.
+ if len(marks) == 0 {
+ return
+ }
+ p0 := fnsym.Func().Text
+ scope := findScope(marks, p0.Pos)
+ for p := p0; p != nil; p = p.Link {
+ if p.Pos == p0.Pos {
+ continue
+ }
+ dwarfScopes[scope].AppendRange(dwarf.Range{Start: p0.Pc, End: p.Pc})
+ p0 = p
+ scope = findScope(marks, p0.Pos)
+ }
+ if p0.Pc < fnsym.Size {
+ dwarfScopes[scope].AppendRange(dwarf.Range{Start: p0.Pc, End: fnsym.Size})
+ }
+}
+
+func compactScopes(dwarfScopes []dwarf.Scope) []dwarf.Scope {
+ // Reverse pass to propagate PC ranges to parent scopes.
+ for i := len(dwarfScopes) - 1; i > 0; i-- {
+ s := &dwarfScopes[i]
+ dwarfScopes[s.Parent].UnifyRanges(s)
+ }
+
+ return dwarfScopes
+}
+
+type varsByScopeAndOffset struct {
+ vars []*dwarf.Var
+ scopes []ScopeID
+}
+
+func (v varsByScopeAndOffset) Len() int {
+ return len(v.vars)
+}
+
+func (v varsByScopeAndOffset) Less(i, j int) bool {
+ if v.scopes[i] != v.scopes[j] {
+ return v.scopes[i] < v.scopes[j]
+ }
+ return v.vars[i].StackOffset < v.vars[j].StackOffset
+}
+
+func (v varsByScopeAndOffset) Swap(i, j int) {
+ v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
+ v.scopes[i], v.scopes[j] = v.scopes[j], v.scopes[i]
+}
diff --git a/src/cmd/compile/internal/gc/scope_test.go b/src/cmd/compile/internal/gc/scope_test.go
new file mode 100644
index 0000000..b0e038d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/scope_test.go
@@ -0,0 +1,538 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc_test
+
+import (
+ "cmd/internal/objfile"
+ "debug/dwarf"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+type testline struct {
+ // line is one line of go source
+ line string
+
+ // scopes is a list of scope IDs of all the lexical scopes that this line
+ // of code belongs to.
+ // Scope IDs are assigned by traversing the tree of lexical blocks of a
+ // function in pre-order
+ // Scope IDs are function specific, i.e. scope 0 is always the root scope
+ // of the function that this line belongs to. Empty scopes are not assigned
+ // an ID (because they are not saved in debug_info).
+ // Scope 0 is always omitted from this list since all lines always belong
+ // to it.
+ scopes []int
+
+ // vars is the list of variables that belong in scopes[len(scopes)-1].
+ // Local variables are prefixed with "var ", formal parameters with "arg ".
+ // Must be ordered alphabetically.
+ // Set to nil to skip the check.
+ vars []string
+
+ // decl is the list of variables declared at this line.
+ decl []string
+
+ // declBefore is the list of variables declared at or before this line.
+ declBefore []string
+}
+
+var testfile = []testline{
+ {line: "package main"},
+ {line: "func f1(x int) { }"},
+ {line: "func f2(x int) { }"},
+ {line: "func f3(x int) { }"},
+ {line: "func f4(x int) { }"},
+ {line: "func f5(x int) { }"},
+ {line: "func f6(x int) { }"},
+ {line: "func fi(x interface{}) { if a, ok := x.(error); ok { a.Error() } }"},
+ {line: "func gret1() int { return 2 }"},
+ {line: "func gretbool() bool { return true }"},
+ {line: "func gret3() (int, int, int) { return 0, 1, 2 }"},
+ {line: "var v = []int{ 0, 1, 2 }"},
+ {line: "var ch = make(chan int)"},
+ {line: "var floatch = make(chan float64)"},
+ {line: "var iface interface{}"},
+ {line: "func TestNestedFor() {", vars: []string{"var a int"}},
+ {line: " a := 0", decl: []string{"a"}},
+ {line: " f1(a)"},
+ {line: " for i := 0; i < 5; i++ {", scopes: []int{1}, vars: []string{"var i int"}, decl: []string{"i"}},
+ {line: " f2(i)", scopes: []int{1}},
+ {line: " for i := 0; i < 5; i++ {", scopes: []int{1, 2}, vars: []string{"var i int"}, decl: []string{"i"}},
+ {line: " f3(i)", scopes: []int{1, 2}},
+ {line: " }"},
+ {line: " f4(i)", scopes: []int{1}},
+ {line: " }"},
+ {line: " f5(a)"},
+ {line: "}"},
+ {line: "func TestOas2() {", vars: []string{}},
+ {line: " if a, b, c := gret3(); a != 1 {", scopes: []int{1}, vars: []string{"var a int", "var b int", "var c int"}},
+ {line: " f1(a)", scopes: []int{1}},
+ {line: " f1(b)", scopes: []int{1}},
+ {line: " f1(c)", scopes: []int{1}},
+ {line: " }"},
+ {line: " for i, x := range v {", scopes: []int{2}, vars: []string{"var i int", "var x int"}},
+ {line: " f1(i)", scopes: []int{2}},
+ {line: " f1(x)", scopes: []int{2}},
+ {line: " }"},
+ {line: " if a, ok := <- ch; ok {", scopes: []int{3}, vars: []string{"var a int", "var ok bool"}},
+ {line: " f1(a)", scopes: []int{3}},
+ {line: " }"},
+ {line: " if a, ok := iface.(int); ok {", scopes: []int{4}, vars: []string{"var a int", "var ok bool"}},
+ {line: " f1(a)", scopes: []int{4}},
+ {line: " }"},
+ {line: "}"},
+ {line: "func TestIfElse() {"},
+ {line: " if x := gret1(); x != 0 {", scopes: []int{1}, vars: []string{"var x int"}},
+ {line: " a := 0", scopes: []int{1, 2}, vars: []string{"var a int"}},
+ {line: " f1(a); f1(x)", scopes: []int{1, 2}},
+ {line: " } else {"},
+ {line: " b := 1", scopes: []int{1, 3}, vars: []string{"var b int"}},
+ {line: " f1(b); f1(x+1)", scopes: []int{1, 3}},
+ {line: " }"},
+ {line: "}"},
+ {line: "func TestSwitch() {", vars: []string{}},
+ {line: " switch x := gret1(); x {", scopes: []int{1}, vars: []string{"var x int"}},
+ {line: " case 0:", scopes: []int{1, 2}},
+ {line: " i := x + 5", scopes: []int{1, 2}, vars: []string{"var i int"}},
+ {line: " f1(x); f1(i)", scopes: []int{1, 2}},
+ {line: " case 1:", scopes: []int{1, 3}},
+ {line: " j := x + 10", scopes: []int{1, 3}, vars: []string{"var j int"}},
+ {line: " f1(x); f1(j)", scopes: []int{1, 3}},
+ {line: " case 2:", scopes: []int{1, 4}},
+ {line: " k := x + 2", scopes: []int{1, 4}, vars: []string{"var k int"}},
+ {line: " f1(x); f1(k)", scopes: []int{1, 4}},
+ {line: " }"},
+ {line: "}"},
+ {line: "func TestTypeSwitch() {", vars: []string{}},
+ {line: " switch x := iface.(type) {"},
+ {line: " case int:", scopes: []int{1}},
+ {line: " f1(x)", scopes: []int{1}, vars: []string{"var x int"}},
+ {line: " case uint8:", scopes: []int{2}},
+ {line: " f1(int(x))", scopes: []int{2}, vars: []string{"var x uint8"}},
+ {line: " case float64:", scopes: []int{3}},
+ {line: " f1(int(x)+1)", scopes: []int{3}, vars: []string{"var x float64"}},
+ {line: " }"},
+ {line: "}"},
+ {line: "func TestSelectScope() {"},
+ {line: " select {"},
+ {line: " case i := <- ch:", scopes: []int{1}},
+ {line: " f1(i)", scopes: []int{1}, vars: []string{"var i int"}},
+ {line: " case f := <- floatch:", scopes: []int{2}},
+ {line: " f1(int(f))", scopes: []int{2}, vars: []string{"var f float64"}},
+ {line: " }"},
+ {line: "}"},
+ {line: "func TestBlock() {", vars: []string{"var a int"}},
+ {line: " a := 1"},
+ {line: " {"},
+ {line: " b := 2", scopes: []int{1}, vars: []string{"var b int"}},
+ {line: " f1(b)", scopes: []int{1}},
+ {line: " f1(a)", scopes: []int{1}},
+ {line: " }"},
+ {line: "}"},
+ {line: "func TestDiscontiguousRanges() {", vars: []string{"var a int"}},
+ {line: " a := 0"},
+ {line: " f1(a)"},
+ {line: " {"},
+ {line: " b := 0", scopes: []int{1}, vars: []string{"var b int"}},
+ {line: " f2(b)", scopes: []int{1}},
+ {line: " if gretbool() {", scopes: []int{1}},
+ {line: " c := 0", scopes: []int{1, 2}, vars: []string{"var c int"}},
+ {line: " f3(c)", scopes: []int{1, 2}},
+ {line: " } else {"},
+ {line: " c := 1.1", scopes: []int{1, 3}, vars: []string{"var c float64"}},
+ {line: " f4(int(c))", scopes: []int{1, 3}},
+ {line: " }"},
+ {line: " f5(b)", scopes: []int{1}},
+ {line: " }"},
+ {line: " f6(a)"},
+ {line: "}"},
+ {line: "func TestClosureScope() {", vars: []string{"var a int", "var b int", "var f func(int)"}},
+ {line: " a := 1; b := 1"},
+ {line: " f := func(c int) {", scopes: []int{0}, vars: []string{"arg c int", "var &b *int", "var a int", "var d int"}, declBefore: []string{"&b", "a"}},
+ {line: " d := 3"},
+ {line: " f1(c); f1(d)"},
+ {line: " if e := 3; e != 0 {", scopes: []int{1}, vars: []string{"var e int"}},
+ {line: " f1(e)", scopes: []int{1}},
+ {line: " f1(a)", scopes: []int{1}},
+ {line: " b = 2", scopes: []int{1}},
+ {line: " }"},
+ {line: " }"},
+ {line: " f(3); f1(b)"},
+ {line: "}"},
+ {line: "func TestEscape() {"},
+ {line: " a := 1", vars: []string{"var a int"}},
+ {line: " {"},
+ {line: " b := 2", scopes: []int{1}, vars: []string{"var &b *int", "var p *int"}},
+ {line: " p := &b", scopes: []int{1}},
+ {line: " f1(a)", scopes: []int{1}},
+ {line: " fi(p)", scopes: []int{1}},
+ {line: " }"},
+ {line: "}"},
+ {line: "func TestCaptureVar(flag bool) func() int {"},
+ {line: " a := 1", vars: []string{"arg flag bool", "arg ~r1 func() int", "var a int"}},
+ {line: " if flag {"},
+ {line: " b := 2", scopes: []int{1}, vars: []string{"var b int", "var f func() int"}},
+ {line: " f := func() int {", scopes: []int{1, 0}},
+ {line: " return b + 1"},
+ {line: " }"},
+ {line: " return f", scopes: []int{1}},
+ {line: " }"},
+ {line: " f1(a)"},
+ {line: " return nil"},
+ {line: "}"},
+ {line: "func main() {"},
+ {line: " TestNestedFor()"},
+ {line: " TestOas2()"},
+ {line: " TestIfElse()"},
+ {line: " TestSwitch()"},
+ {line: " TestTypeSwitch()"},
+ {line: " TestSelectScope()"},
+ {line: " TestBlock()"},
+ {line: " TestDiscontiguousRanges()"},
+ {line: " TestClosureScope()"},
+ {line: " TestEscape()"},
+ {line: " TestCaptureVar(true)"},
+ {line: "}"},
+}
+
+const detailOutput = false
+
+// Compiles testfile checks that the description of lexical blocks emitted
+// by the linker in debug_info, for each function in the main package,
+// corresponds to what we expect it to be.
+func TestScopeRanges(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ t.Parallel()
+
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; no DWARF symbol table in executables")
+ }
+
+ dir, err := ioutil.TempDir("", "TestScopeRanges")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ src, f := gobuild(t, dir, false, testfile)
+ defer f.Close()
+
+ // the compiler uses forward slashes for paths even on windows
+ src = strings.Replace(src, "\\", "/", -1)
+
+ pcln, err := f.PCLineTable()
+ if err != nil {
+ t.Fatal(err)
+ }
+ dwarfData, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+ dwarfReader := dwarfData.Reader()
+
+ lines := make(map[line][]*lexblock)
+
+ for {
+ entry, err := dwarfReader.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if entry == nil {
+ break
+ }
+
+ if entry.Tag != dwarf.TagSubprogram {
+ continue
+ }
+
+ name, ok := entry.Val(dwarf.AttrName).(string)
+ if !ok || !strings.HasPrefix(name, "main.Test") {
+ continue
+ }
+
+ var scope lexblock
+ ctxt := scopexplainContext{
+ dwarfData: dwarfData,
+ dwarfReader: dwarfReader,
+ scopegen: 1,
+ }
+
+ readScope(&ctxt, &scope, entry)
+
+ scope.markLines(pcln, lines)
+ }
+
+ anyerror := false
+ for i := range testfile {
+ tgt := testfile[i].scopes
+ out := lines[line{src, i + 1}]
+
+ if detailOutput {
+ t.Logf("%s // %v", testfile[i].line, out)
+ }
+
+ scopesok := checkScopes(tgt, out)
+ if !scopesok {
+ t.Logf("mismatch at line %d %q: expected: %v got: %v\n", i, testfile[i].line, tgt, scopesToString(out))
+ }
+
+ varsok := true
+ if testfile[i].vars != nil {
+ if len(out) > 0 {
+ varsok = checkVars(testfile[i].vars, out[len(out)-1].vars)
+ if !varsok {
+ t.Logf("variable mismatch at line %d %q for scope %d: expected: %v got: %v\n", i+1, testfile[i].line, out[len(out)-1].id, testfile[i].vars, out[len(out)-1].vars)
+ }
+ for j := range testfile[i].decl {
+ if line := declLineForVar(out[len(out)-1].vars, testfile[i].decl[j]); line != i+1 {
+ t.Errorf("wrong declaration line for variable %s, expected %d got: %d", testfile[i].decl[j], i+1, line)
+ }
+ }
+
+ for j := range testfile[i].declBefore {
+ if line := declLineForVar(out[len(out)-1].vars, testfile[i].declBefore[j]); line > i+1 {
+ t.Errorf("wrong declaration line for variable %s, expected %d (or less) got: %d", testfile[i].declBefore[j], i+1, line)
+ }
+ }
+ }
+ }
+
+ anyerror = anyerror || !scopesok || !varsok
+ }
+
+ if anyerror {
+ t.Fatalf("mismatched output")
+ }
+}
+
+func scopesToString(v []*lexblock) string {
+ r := make([]string, len(v))
+ for i, s := range v {
+ r[i] = strconv.Itoa(s.id)
+ }
+ return "[ " + strings.Join(r, ", ") + " ]"
+}
+
+func checkScopes(tgt []int, out []*lexblock) bool {
+ if len(out) > 0 {
+ // omit scope 0
+ out = out[1:]
+ }
+ if len(tgt) != len(out) {
+ return false
+ }
+ for i := range tgt {
+ if tgt[i] != out[i].id {
+ return false
+ }
+ }
+ return true
+}
+
+func checkVars(tgt []string, out []variable) bool {
+ if len(tgt) != len(out) {
+ return false
+ }
+ for i := range tgt {
+ if tgt[i] != out[i].expr {
+ return false
+ }
+ }
+ return true
+}
+
+func declLineForVar(scope []variable, name string) int {
+ for i := range scope {
+ if scope[i].name() == name {
+ return scope[i].declLine
+ }
+ }
+ return -1
+}
+
+type lexblock struct {
+ id int
+ ranges [][2]uint64
+ vars []variable
+ scopes []lexblock
+}
+
+type variable struct {
+ expr string
+ declLine int
+}
+
+func (v *variable) name() string {
+ return strings.Split(v.expr, " ")[1]
+}
+
+type line struct {
+ file string
+ lineno int
+}
+
+type scopexplainContext struct {
+ dwarfData *dwarf.Data
+ dwarfReader *dwarf.Reader
+ scopegen int
+}
+
+// readScope reads the DW_TAG_lexical_block or the DW_TAG_subprogram in
+// entry and writes a description in scope.
+// Nested DW_TAG_lexical_block entries are read recursively.
+func readScope(ctxt *scopexplainContext, scope *lexblock, entry *dwarf.Entry) {
+ var err error
+ scope.ranges, err = ctxt.dwarfData.Ranges(entry)
+ if err != nil {
+ panic(err)
+ }
+ for {
+ e, err := ctxt.dwarfReader.Next()
+ if err != nil {
+ panic(err)
+ }
+ switch e.Tag {
+ case 0:
+ sort.Slice(scope.vars, func(i, j int) bool {
+ return scope.vars[i].expr < scope.vars[j].expr
+ })
+ return
+ case dwarf.TagFormalParameter:
+ typ, err := ctxt.dwarfData.Type(e.Val(dwarf.AttrType).(dwarf.Offset))
+ if err != nil {
+ panic(err)
+ }
+ scope.vars = append(scope.vars, entryToVar(e, "arg", typ))
+ case dwarf.TagVariable:
+ typ, err := ctxt.dwarfData.Type(e.Val(dwarf.AttrType).(dwarf.Offset))
+ if err != nil {
+ panic(err)
+ }
+ scope.vars = append(scope.vars, entryToVar(e, "var", typ))
+ case dwarf.TagLexDwarfBlock:
+ scope.scopes = append(scope.scopes, lexblock{id: ctxt.scopegen})
+ ctxt.scopegen++
+ readScope(ctxt, &scope.scopes[len(scope.scopes)-1], e)
+ }
+ }
+}
+
+func entryToVar(e *dwarf.Entry, kind string, typ dwarf.Type) variable {
+ return variable{
+ fmt.Sprintf("%s %s %s", kind, e.Val(dwarf.AttrName).(string), typ.String()),
+ int(e.Val(dwarf.AttrDeclLine).(int64)),
+ }
+}
+
+// markLines marks all lines that belong to this scope with this scope
+// Recursively calls markLines for all children scopes.
+func (scope *lexblock) markLines(pcln objfile.Liner, lines map[line][]*lexblock) {
+ for _, r := range scope.ranges {
+ for pc := r[0]; pc < r[1]; pc++ {
+ file, lineno, _ := pcln.PCToLine(pc)
+ l := line{file, lineno}
+ if len(lines[l]) == 0 || lines[l][len(lines[l])-1] != scope {
+ lines[l] = append(lines[l], scope)
+ }
+ }
+ }
+
+ for i := range scope.scopes {
+ scope.scopes[i].markLines(pcln, lines)
+ }
+}
+
+func gobuild(t *testing.T, dir string, optimized bool, testfile []testline) (string, *objfile.File) {
+ src := filepath.Join(dir, "test.go")
+ dst := filepath.Join(dir, "out.o")
+
+ f, err := os.Create(src)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for i := range testfile {
+ f.Write([]byte(testfile[i].line))
+ f.Write([]byte{'\n'})
+ }
+ f.Close()
+
+ args := []string{"build"}
+ if !optimized {
+ args = append(args, "-gcflags=-N -l")
+ }
+ args = append(args, "-o", dst, src)
+
+ cmd := exec.Command(testenv.GoToolPath(t), args...)
+ if b, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("build: %s\n", string(b))
+ t.Fatal(err)
+ }
+
+ pkg, err := objfile.Open(dst)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return src, pkg
+}
+
+// TestEmptyDwarfRanges tests that no list entry in debug_ranges has start == end.
+// See issue #23928.
+func TestEmptyDwarfRanges(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+ t.Parallel()
+
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; no DWARF symbol table in executables")
+ }
+
+ dir, err := ioutil.TempDir("", "TestEmptyDwarfRanges")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ _, f := gobuild(t, dir, true, []testline{{line: "package main"}, {line: "func main(){ println(\"hello\") }"}})
+ defer f.Close()
+
+ dwarfData, err := f.DWARF()
+ if err != nil {
+ t.Fatal(err)
+ }
+ dwarfReader := dwarfData.Reader()
+
+ for {
+ entry, err := dwarfReader.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if entry == nil {
+ break
+ }
+
+ ranges, err := dwarfData.Ranges(entry)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if ranges == nil {
+ continue
+ }
+
+ for _, rng := range ranges {
+ if rng[0] == rng[1] {
+ t.Errorf("range entry with start == end: %v", rng)
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
new file mode 100644
index 0000000..97e0424
--- /dev/null
+++ b/src/cmd/compile/internal/gc/select.go
@@ -0,0 +1,387 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import "cmd/compile/internal/types"
+
+// select
+func typecheckselect(sel *Node) {
+ var def *Node
+ lno := setlineno(sel)
+ typecheckslice(sel.Ninit.Slice(), ctxStmt)
+ for _, ncase := range sel.List.Slice() {
+ if ncase.Op != OCASE {
+ setlineno(ncase)
+ Fatalf("typecheckselect %v", ncase.Op)
+ }
+
+ if ncase.List.Len() == 0 {
+ // default
+ if def != nil {
+ yyerrorl(ncase.Pos, "multiple defaults in select (first at %v)", def.Line())
+ } else {
+ def = ncase
+ }
+ } else if ncase.List.Len() > 1 {
+ yyerrorl(ncase.Pos, "select cases cannot be lists")
+ } else {
+ ncase.List.SetFirst(typecheck(ncase.List.First(), ctxStmt))
+ n := ncase.List.First()
+ ncase.Left = n
+ ncase.List.Set(nil)
+ switch n.Op {
+ default:
+ pos := n.Pos
+ if n.Op == ONAME {
+ // We don't have the right position for ONAME nodes (see #15459 and
+ // others). Using ncase.Pos for now as it will provide the correct
+ // line number (assuming the expression follows the "case" keyword
+ // on the same line). This matches the approach before 1.10.
+ pos = ncase.Pos
+ }
+ yyerrorl(pos, "select case must be receive, send or assign recv")
+
+ // convert x = <-c into OSELRECV(x, <-c).
+ // remove implicit conversions; the eventual assignment
+ // will reintroduce them.
+ case OAS:
+ if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit() {
+ n.Right = n.Right.Left
+ }
+
+ if n.Right.Op != ORECV {
+ yyerrorl(n.Pos, "select assignment must have receive on right hand side")
+ break
+ }
+
+ n.Op = OSELRECV
+
+ // convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
+ case OAS2RECV:
+ if n.Right.Op != ORECV {
+ yyerrorl(n.Pos, "select assignment must have receive on right hand side")
+ break
+ }
+
+ n.Op = OSELRECV2
+ n.Left = n.List.First()
+ n.List.Set1(n.List.Second())
+
+ // convert <-c into OSELRECV(N, <-c)
+ case ORECV:
+ n = nodl(n.Pos, OSELRECV, nil, n)
+
+ n.SetTypecheck(1)
+ ncase.Left = n
+
+ case OSEND:
+ break
+ }
+ }
+
+ typecheckslice(ncase.Nbody.Slice(), ctxStmt)
+ }
+
+ lineno = lno
+}
+
+func walkselect(sel *Node) {
+ lno := setlineno(sel)
+ if sel.Nbody.Len() != 0 {
+ Fatalf("double walkselect")
+ }
+
+ init := sel.Ninit.Slice()
+ sel.Ninit.Set(nil)
+
+ init = append(init, walkselectcases(&sel.List)...)
+ sel.List.Set(nil)
+
+ sel.Nbody.Set(init)
+ walkstmtlist(sel.Nbody.Slice())
+
+ lineno = lno
+}
+
+func walkselectcases(cases *Nodes) []*Node {
+ ncas := cases.Len()
+ sellineno := lineno
+
+ // optimization: zero-case select
+ if ncas == 0 {
+ return []*Node{mkcall("block", nil, nil)}
+ }
+
+ // optimization: one-case select: single op.
+ if ncas == 1 {
+ cas := cases.First()
+ setlineno(cas)
+ l := cas.Ninit.Slice()
+ if cas.Left != nil { // not default:
+ n := cas.Left
+ l = append(l, n.Ninit.Slice()...)
+ n.Ninit.Set(nil)
+ switch n.Op {
+ default:
+ Fatalf("select %v", n.Op)
+
+ case OSEND:
+ // already ok
+
+ case OSELRECV, OSELRECV2:
+ if n.Op == OSELRECV || n.List.Len() == 0 {
+ if n.Left == nil {
+ n = n.Right
+ } else {
+ n.Op = OAS
+ }
+ break
+ }
+
+ if n.Left == nil {
+ nblank = typecheck(nblank, ctxExpr|ctxAssign)
+ n.Left = nblank
+ }
+
+ n.Op = OAS2
+ n.List.Prepend(n.Left)
+ n.Rlist.Set1(n.Right)
+ n.Right = nil
+ n.Left = nil
+ n.SetTypecheck(0)
+ n = typecheck(n, ctxStmt)
+ }
+
+ l = append(l, n)
+ }
+
+ l = append(l, cas.Nbody.Slice()...)
+ l = append(l, nod(OBREAK, nil, nil))
+ return l
+ }
+
+ // convert case value arguments to addresses.
+ // this rewrite is used by both the general code and the next optimization.
+ var dflt *Node
+ for _, cas := range cases.Slice() {
+ setlineno(cas)
+ n := cas.Left
+ if n == nil {
+ dflt = cas
+ continue
+ }
+ switch n.Op {
+ case OSEND:
+ n.Right = nod(OADDR, n.Right, nil)
+ n.Right = typecheck(n.Right, ctxExpr)
+
+ case OSELRECV, OSELRECV2:
+ if n.Op == OSELRECV2 && n.List.Len() == 0 {
+ n.Op = OSELRECV
+ }
+
+ if n.Left != nil {
+ n.Left = nod(OADDR, n.Left, nil)
+ n.Left = typecheck(n.Left, ctxExpr)
+ }
+ }
+ }
+
+ // optimization: two-case select but one is default: single non-blocking op.
+ if ncas == 2 && dflt != nil {
+ cas := cases.First()
+ if cas == dflt {
+ cas = cases.Second()
+ }
+
+ n := cas.Left
+ setlineno(n)
+ r := nod(OIF, nil, nil)
+ r.Ninit.Set(cas.Ninit.Slice())
+ switch n.Op {
+ default:
+ Fatalf("select %v", n.Op)
+
+ case OSEND:
+ // if selectnbsend(c, v) { body } else { default body }
+ ch := n.Left
+ r.Left = mkcall1(chanfn("selectnbsend", 2, ch.Type), types.Types[TBOOL], &r.Ninit, ch, n.Right)
+
+ case OSELRECV:
+ // if selectnbrecv(&v, c) { body } else { default body }
+ ch := n.Right.Left
+ elem := n.Left
+ if elem == nil {
+ elem = nodnil()
+ }
+ r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, ch)
+
+ case OSELRECV2:
+ // if selectnbrecv2(&v, &received, c) { body } else { default body }
+ ch := n.Right.Left
+ elem := n.Left
+ if elem == nil {
+ elem = nodnil()
+ }
+ receivedp := nod(OADDR, n.List.First(), nil)
+ receivedp = typecheck(receivedp, ctxExpr)
+ r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, receivedp, ch)
+ }
+
+ r.Left = typecheck(r.Left, ctxExpr)
+ r.Nbody.Set(cas.Nbody.Slice())
+ r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.Nbody.Slice()...))
+ return []*Node{r, nod(OBREAK, nil, nil)}
+ }
+
+ if dflt != nil {
+ ncas--
+ }
+ casorder := make([]*Node, ncas)
+ nsends, nrecvs := 0, 0
+
+ var init []*Node
+
+ // generate sel-struct
+ lineno = sellineno
+ selv := temp(types.NewArray(scasetype(), int64(ncas)))
+ r := nod(OAS, selv, nil)
+ r = typecheck(r, ctxStmt)
+ init = append(init, r)
+
+ // No initialization for order; runtime.selectgo is responsible for that.
+ order := temp(types.NewArray(types.Types[TUINT16], 2*int64(ncas)))
+
+ var pc0, pcs *Node
+ if flag_race {
+ pcs = temp(types.NewArray(types.Types[TUINTPTR], int64(ncas)))
+ pc0 = typecheck(nod(OADDR, nod(OINDEX, pcs, nodintconst(0)), nil), ctxExpr)
+ } else {
+ pc0 = nodnil()
+ }
+
+ // register cases
+ for _, cas := range cases.Slice() {
+ setlineno(cas)
+
+ init = append(init, cas.Ninit.Slice()...)
+ cas.Ninit.Set(nil)
+
+ n := cas.Left
+ if n == nil { // default:
+ continue
+ }
+
+ var i int
+ var c, elem *Node
+ switch n.Op {
+ default:
+ Fatalf("select %v", n.Op)
+ case OSEND:
+ i = nsends
+ nsends++
+ c = n.Left
+ elem = n.Right
+ case OSELRECV, OSELRECV2:
+ nrecvs++
+ i = ncas - nrecvs
+ c = n.Right.Left
+ elem = n.Left
+ }
+
+ casorder[i] = cas
+
+ setField := func(f string, val *Node) {
+ r := nod(OAS, nodSym(ODOT, nod(OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
+ r = typecheck(r, ctxStmt)
+ init = append(init, r)
+ }
+
+ c = convnop(c, types.Types[TUNSAFEPTR])
+ setField("c", c)
+ if elem != nil {
+ elem = convnop(elem, types.Types[TUNSAFEPTR])
+ setField("elem", elem)
+ }
+
+ // TODO(mdempsky): There should be a cleaner way to
+ // handle this.
+ if flag_race {
+ r = mkcall("selectsetpc", nil, nil, nod(OADDR, nod(OINDEX, pcs, nodintconst(int64(i))), nil))
+ init = append(init, r)
+ }
+ }
+ if nsends+nrecvs != ncas {
+ Fatalf("walkselectcases: miscount: %v + %v != %v", nsends, nrecvs, ncas)
+ }
+
+ // run the select
+ lineno = sellineno
+ chosen := temp(types.Types[TINT])
+ recvOK := temp(types.Types[TBOOL])
+ r = nod(OAS2, nil, nil)
+ r.List.Set2(chosen, recvOK)
+ fn := syslook("selectgo")
+ r.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, nodintconst(int64(nsends)), nodintconst(int64(nrecvs)), nodbool(dflt == nil)))
+ r = typecheck(r, ctxStmt)
+ init = append(init, r)
+
+ // selv and order are no longer alive after selectgo.
+ init = append(init, nod(OVARKILL, selv, nil))
+ init = append(init, nod(OVARKILL, order, nil))
+ if flag_race {
+ init = append(init, nod(OVARKILL, pcs, nil))
+ }
+
+ // dispatch cases
+ dispatch := func(cond, cas *Node) {
+ cond = typecheck(cond, ctxExpr)
+ cond = defaultlit(cond, nil)
+
+ r := nod(OIF, cond, nil)
+
+ if n := cas.Left; n != nil && n.Op == OSELRECV2 {
+ x := nod(OAS, n.List.First(), recvOK)
+ x = typecheck(x, ctxStmt)
+ r.Nbody.Append(x)
+ }
+
+ r.Nbody.AppendNodes(&cas.Nbody)
+ r.Nbody.Append(nod(OBREAK, nil, nil))
+ init = append(init, r)
+ }
+
+ if dflt != nil {
+ setlineno(dflt)
+ dispatch(nod(OLT, chosen, nodintconst(0)), dflt)
+ }
+ for i, cas := range casorder {
+ setlineno(cas)
+ dispatch(nod(OEQ, chosen, nodintconst(int64(i))), cas)
+ }
+
+ return init
+}
+
+// bytePtrToIndex returns a Node representing "(*byte)(&n[i])".
+func bytePtrToIndex(n *Node, i int64) *Node {
+ s := nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil)
+ t := types.NewPtr(types.Types[TUINT8])
+ return convnop(s, t)
+}
+
+var scase *types.Type
+
+// Keep in sync with src/runtime/select.go.
+func scasetype() *types.Type {
+ if scase == nil {
+ scase = tostruct([]*Node{
+ namedfield("c", types.Types[TUNSAFEPTR]),
+ namedfield("elem", types.Types[TUNSAFEPTR]),
+ })
+ scase.SetNoalg(true)
+ }
+ return scase
+}
diff --git a/src/cmd/compile/internal/gc/shift_test.go b/src/cmd/compile/internal/gc/shift_test.go
new file mode 100644
index 0000000..ce2eedf
--- /dev/null
+++ b/src/cmd/compile/internal/gc/shift_test.go
@@ -0,0 +1,1031 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "reflect"
+ "testing"
+)
+
+// Tests shifts of zero.
+
+//go:noinline
+func ofz64l64(n uint64) int64 {
+ var x int64
+ return x << n
+}
+
+//go:noinline
+func ofz64l32(n uint32) int64 {
+ var x int64
+ return x << n
+}
+
+//go:noinline
+func ofz64l16(n uint16) int64 {
+ var x int64
+ return x << n
+}
+
+//go:noinline
+func ofz64l8(n uint8) int64 {
+ var x int64
+ return x << n
+}
+
+//go:noinline
+func ofz64r64(n uint64) int64 {
+ var x int64
+ return x >> n
+}
+
+//go:noinline
+func ofz64r32(n uint32) int64 {
+ var x int64
+ return x >> n
+}
+
+//go:noinline
+func ofz64r16(n uint16) int64 {
+ var x int64
+ return x >> n
+}
+
+//go:noinline
+func ofz64r8(n uint8) int64 {
+ var x int64
+ return x >> n
+}
+
+//go:noinline
+func ofz64ur64(n uint64) uint64 {
+ var x uint64
+ return x >> n
+}
+
+//go:noinline
+func ofz64ur32(n uint32) uint64 {
+ var x uint64
+ return x >> n
+}
+
+//go:noinline
+func ofz64ur16(n uint16) uint64 {
+ var x uint64
+ return x >> n
+}
+
+//go:noinline
+func ofz64ur8(n uint8) uint64 {
+ var x uint64
+ return x >> n
+}
+
+//go:noinline
+func ofz32l64(n uint64) int32 {
+ var x int32
+ return x << n
+}
+
+//go:noinline
+func ofz32l32(n uint32) int32 {
+ var x int32
+ return x << n
+}
+
+//go:noinline
+func ofz32l16(n uint16) int32 {
+ var x int32
+ return x << n
+}
+
+//go:noinline
+func ofz32l8(n uint8) int32 {
+ var x int32
+ return x << n
+}
+
+//go:noinline
+func ofz32r64(n uint64) int32 {
+ var x int32
+ return x >> n
+}
+
+//go:noinline
+func ofz32r32(n uint32) int32 {
+ var x int32
+ return x >> n
+}
+
+//go:noinline
+func ofz32r16(n uint16) int32 {
+ var x int32
+ return x >> n
+}
+
+//go:noinline
+func ofz32r8(n uint8) int32 {
+ var x int32
+ return x >> n
+}
+
+//go:noinline
+func ofz32ur64(n uint64) uint32 {
+ var x uint32
+ return x >> n
+}
+
+//go:noinline
+func ofz32ur32(n uint32) uint32 {
+ var x uint32
+ return x >> n
+}
+
+//go:noinline
+func ofz32ur16(n uint16) uint32 {
+ var x uint32
+ return x >> n
+}
+
+//go:noinline
+func ofz32ur8(n uint8) uint32 {
+ var x uint32
+ return x >> n
+}
+
+//go:noinline
+func ofz16l64(n uint64) int16 {
+ var x int16
+ return x << n
+}
+
+//go:noinline
+func ofz16l32(n uint32) int16 {
+ var x int16
+ return x << n
+}
+
+//go:noinline
+func ofz16l16(n uint16) int16 {
+ var x int16
+ return x << n
+}
+
+//go:noinline
+func ofz16l8(n uint8) int16 {
+ var x int16
+ return x << n
+}
+
+//go:noinline
+func ofz16r64(n uint64) int16 {
+ var x int16
+ return x >> n
+}
+
+//go:noinline
+func ofz16r32(n uint32) int16 {
+ var x int16
+ return x >> n
+}
+
+//go:noinline
+func ofz16r16(n uint16) int16 {
+ var x int16
+ return x >> n
+}
+
+//go:noinline
+func ofz16r8(n uint8) int16 {
+ var x int16
+ return x >> n
+}
+
+//go:noinline
+func ofz16ur64(n uint64) uint16 {
+ var x uint16
+ return x >> n
+}
+
+//go:noinline
+func ofz16ur32(n uint32) uint16 {
+ var x uint16
+ return x >> n
+}
+
+//go:noinline
+func ofz16ur16(n uint16) uint16 {
+ var x uint16
+ return x >> n
+}
+
+//go:noinline
+func ofz16ur8(n uint8) uint16 {
+ var x uint16
+ return x >> n
+}
+
+//go:noinline
+func ofz8l64(n uint64) int8 {
+ var x int8
+ return x << n
+}
+
+//go:noinline
+func ofz8l32(n uint32) int8 {
+ var x int8
+ return x << n
+}
+
+//go:noinline
+func ofz8l16(n uint16) int8 {
+ var x int8
+ return x << n
+}
+
+//go:noinline
+func ofz8l8(n uint8) int8 {
+ var x int8
+ return x << n
+}
+
+//go:noinline
+func ofz8r64(n uint64) int8 {
+ var x int8
+ return x >> n
+}
+
+//go:noinline
+func ofz8r32(n uint32) int8 {
+ var x int8
+ return x >> n
+}
+
+//go:noinline
+func ofz8r16(n uint16) int8 {
+ var x int8
+ return x >> n
+}
+
+//go:noinline
+func ofz8r8(n uint8) int8 {
+ var x int8
+ return x >> n
+}
+
+//go:noinline
+func ofz8ur64(n uint64) uint8 {
+ var x uint8
+ return x >> n
+}
+
+//go:noinline
+func ofz8ur32(n uint32) uint8 {
+ var x uint8
+ return x >> n
+}
+
+//go:noinline
+func ofz8ur16(n uint16) uint8 {
+ var x uint8
+ return x >> n
+}
+
+//go:noinline
+func ofz8ur8(n uint8) uint8 {
+ var x uint8
+ return x >> n
+}
+
+func TestShiftOfZero(t *testing.T) {
+ if got := ofz64l64(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz64l32(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz64l16(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz64l8(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz64r64(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz64r32(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz64r16(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz64r8(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz64ur64(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz64ur32(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz64ur16(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz64ur8(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+
+ if got := ofz32l64(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz32l32(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz32l16(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz32l8(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz32r64(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz32r32(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz32r16(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz32r8(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz32ur64(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz32ur32(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz32ur16(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz32ur8(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+
+ if got := ofz16l64(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz16l32(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz16l16(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz16l8(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz16r64(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz16r32(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz16r16(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz16r8(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz16ur64(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz16ur32(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz16ur16(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz16ur8(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+
+ if got := ofz8l64(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz8l32(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz8l16(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz8l8(5); got != 0 {
+ t.Errorf("0<<5 == %d, want 0", got)
+ }
+ if got := ofz8r64(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz8r32(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz8r16(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz8r8(5); got != 0 {
+ t.Errorf("0>>5 == %d, want 0", got)
+ }
+ if got := ofz8ur64(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz8ur32(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz8ur16(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+ if got := ofz8ur8(5); got != 0 {
+ t.Errorf("0>>>5 == %d, want 0", got)
+ }
+}
+
+//go:noinline
+func byz64l(n int64) int64 {
+ return n << 0
+}
+
+//go:noinline
+func byz64r(n int64) int64 {
+ return n >> 0
+}
+
+//go:noinline
+func byz64ur(n uint64) uint64 {
+ return n >> 0
+}
+
+//go:noinline
+func byz32l(n int32) int32 {
+ return n << 0
+}
+
+//go:noinline
+func byz32r(n int32) int32 {
+ return n >> 0
+}
+
+//go:noinline
+func byz32ur(n uint32) uint32 {
+ return n >> 0
+}
+
+//go:noinline
+func byz16l(n int16) int16 {
+ return n << 0
+}
+
+//go:noinline
+func byz16r(n int16) int16 {
+ return n >> 0
+}
+
+//go:noinline
+func byz16ur(n uint16) uint16 {
+ return n >> 0
+}
+
+//go:noinline
+func byz8l(n int8) int8 {
+ return n << 0
+}
+
+//go:noinline
+func byz8r(n int8) int8 {
+ return n >> 0
+}
+
+//go:noinline
+func byz8ur(n uint8) uint8 {
+ return n >> 0
+}
+
+func TestShiftByZero(t *testing.T) {
+ {
+ var n int64 = 0x5555555555555555
+ if got := byz64l(n); got != n {
+ t.Errorf("%x<<0 == %x, want %x", n, got, n)
+ }
+ if got := byz64r(n); got != n {
+ t.Errorf("%x>>0 == %x, want %x", n, got, n)
+ }
+ }
+ {
+ var n uint64 = 0xaaaaaaaaaaaaaaaa
+ if got := byz64ur(n); got != n {
+ t.Errorf("%x>>>0 == %x, want %x", n, got, n)
+ }
+ }
+
+ {
+ var n int32 = 0x55555555
+ if got := byz32l(n); got != n {
+ t.Errorf("%x<<0 == %x, want %x", n, got, n)
+ }
+ if got := byz32r(n); got != n {
+ t.Errorf("%x>>0 == %x, want %x", n, got, n)
+ }
+ }
+ {
+ var n uint32 = 0xaaaaaaaa
+ if got := byz32ur(n); got != n {
+ t.Errorf("%x>>>0 == %x, want %x", n, got, n)
+ }
+ }
+
+ {
+ var n int16 = 0x5555
+ if got := byz16l(n); got != n {
+ t.Errorf("%x<<0 == %x, want %x", n, got, n)
+ }
+ if got := byz16r(n); got != n {
+ t.Errorf("%x>>0 == %x, want %x", n, got, n)
+ }
+ }
+ {
+ var n uint16 = 0xaaaa
+ if got := byz16ur(n); got != n {
+ t.Errorf("%x>>>0 == %x, want %x", n, got, n)
+ }
+ }
+
+ {
+ var n int8 = 0x55
+ if got := byz8l(n); got != n {
+ t.Errorf("%x<<0 == %x, want %x", n, got, n)
+ }
+ if got := byz8r(n); got != n {
+ t.Errorf("%x>>0 == %x, want %x", n, got, n)
+ }
+ }
+ {
+ var n uint8 = 0x55
+ if got := byz8ur(n); got != n {
+ t.Errorf("%x>>>0 == %x, want %x", n, got, n)
+ }
+ }
+}
+
+//go:noinline
+func two64l(x int64) int64 {
+ return x << 1 << 1
+}
+
+//go:noinline
+func two64r(x int64) int64 {
+ return x >> 1 >> 1
+}
+
+//go:noinline
+func two64ur(x uint64) uint64 {
+ return x >> 1 >> 1
+}
+
+//go:noinline
+func two32l(x int32) int32 {
+ return x << 1 << 1
+}
+
+//go:noinline
+func two32r(x int32) int32 {
+ return x >> 1 >> 1
+}
+
+//go:noinline
+func two32ur(x uint32) uint32 {
+ return x >> 1 >> 1
+}
+
+//go:noinline
+func two16l(x int16) int16 {
+ return x << 1 << 1
+}
+
+//go:noinline
+func two16r(x int16) int16 {
+ return x >> 1 >> 1
+}
+
+//go:noinline
+func two16ur(x uint16) uint16 {
+ return x >> 1 >> 1
+}
+
+//go:noinline
+func two8l(x int8) int8 {
+ return x << 1 << 1
+}
+
+//go:noinline
+func two8r(x int8) int8 {
+ return x >> 1 >> 1
+}
+
+//go:noinline
+func two8ur(x uint8) uint8 {
+ return x >> 1 >> 1
+}
+
+func TestShiftCombine(t *testing.T) {
+ if got, want := two64l(4), int64(16); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := two64r(64), int64(16); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := two64ur(64), uint64(16); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := two32l(4), int32(16); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := two32r(64), int32(16); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := two32ur(64), uint32(16); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := two16l(4), int16(16); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := two16r(64), int16(16); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := two16ur(64), uint16(16); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := two8l(4), int8(16); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := two8r(64), int8(16); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := two8ur(64), uint8(16); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+
+}
+
+//go:noinline
+func three64l(x int64) int64 {
+ return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three64ul(x uint64) uint64 {
+ return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three64r(x int64) int64 {
+ return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three64ur(x uint64) uint64 {
+ return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three32l(x int32) int32 {
+ return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three32ul(x uint32) uint32 {
+ return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three32r(x int32) int32 {
+ return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three32ur(x uint32) uint32 {
+ return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three16l(x int16) int16 {
+ return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three16ul(x uint16) uint16 {
+ return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three16r(x int16) int16 {
+ return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three16ur(x uint16) uint16 {
+ return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three8l(x int8) int8 {
+ return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three8ul(x uint8) uint8 {
+ return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three8r(x int8) int8 {
+ return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three8ur(x uint8) uint8 {
+ return x >> 3 << 1 >> 2
+}
+
+func TestShiftCombine3(t *testing.T) {
+ if got, want := three64l(4), int64(64); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := three64ul(4), uint64(64); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := three64r(64), int64(4); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := three64ur(64), uint64(4); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := three32l(4), int32(64); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := three32ul(4), uint32(64); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := three32r(64), int32(4); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := three32ur(64), uint32(4); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := three16l(4), int16(64); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := three16ul(4), uint16(64); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := three16r(64), int16(4); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := three16ur(64), uint16(4); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := three8l(4), int8(64); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := three8ul(4), uint8(64); want != got {
+ t.Errorf("4<<1<<1 == %d, want %d", got, want)
+ }
+ if got, want := three8r(64), int8(4); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+ if got, want := three8ur(64), uint8(4); want != got {
+ t.Errorf("64>>1>>1 == %d, want %d", got, want)
+ }
+}
+
+var (
+ one64 int64 = 1
+ one64u uint64 = 1
+ one32 int32 = 1
+ one32u uint32 = 1
+ one16 int16 = 1
+ one16u uint16 = 1
+ one8 int8 = 1
+ one8u uint8 = 1
+)
+
+func TestShiftLargeCombine(t *testing.T) {
+ var N uint64 = 0x8000000000000000
+ if one64<<N<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one64>>N>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one64u>>N>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one32<<N<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one32>>N>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one32u>>N>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one16<<N<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one16>>N>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one16u>>N>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one8<<N<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one8>>N>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one8u>>N>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+}
+
+func TestShiftLargeCombine3(t *testing.T) {
+ var N uint64 = 0x8000000000000001
+ if one64<<N>>2<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one64u<<N>>2<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one64>>N<<2>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one64u>>N<<2>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one32<<N>>2<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one32u<<N>>2<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one32>>N<<2>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one32u>>N<<2>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one16<<N>>2<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one16u<<N>>2<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one16>>N<<2>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one16u>>N<<2>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one8<<N>>2<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one8u<<N>>2<<N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one8>>N<<2>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+ if one8u>>N<<2>>N == 1 {
+ t.Errorf("shift overflow mishandled")
+ }
+}
+
+func TestShiftGeneric(t *testing.T) {
+ for _, test := range [...]struct {
+ valueWidth int
+ signed bool
+ shiftWidth int
+ left bool
+ f interface{}
+ }{
+ {64, true, 64, true, func(n int64, s uint64) int64 { return n << s }},
+ {64, true, 64, false, func(n int64, s uint64) int64 { return n >> s }},
+ {64, false, 64, false, func(n uint64, s uint64) uint64 { return n >> s }},
+ {64, true, 32, true, func(n int64, s uint32) int64 { return n << s }},
+ {64, true, 32, false, func(n int64, s uint32) int64 { return n >> s }},
+ {64, false, 32, false, func(n uint64, s uint32) uint64 { return n >> s }},
+ {64, true, 16, true, func(n int64, s uint16) int64 { return n << s }},
+ {64, true, 16, false, func(n int64, s uint16) int64 { return n >> s }},
+ {64, false, 16, false, func(n uint64, s uint16) uint64 { return n >> s }},
+ {64, true, 8, true, func(n int64, s uint8) int64 { return n << s }},
+ {64, true, 8, false, func(n int64, s uint8) int64 { return n >> s }},
+ {64, false, 8, false, func(n uint64, s uint8) uint64 { return n >> s }},
+
+ {32, true, 64, true, func(n int32, s uint64) int32 { return n << s }},
+ {32, true, 64, false, func(n int32, s uint64) int32 { return n >> s }},
+ {32, false, 64, false, func(n uint32, s uint64) uint32 { return n >> s }},
+ {32, true, 32, true, func(n int32, s uint32) int32 { return n << s }},
+ {32, true, 32, false, func(n int32, s uint32) int32 { return n >> s }},
+ {32, false, 32, false, func(n uint32, s uint32) uint32 { return n >> s }},
+ {32, true, 16, true, func(n int32, s uint16) int32 { return n << s }},
+ {32, true, 16, false, func(n int32, s uint16) int32 { return n >> s }},
+ {32, false, 16, false, func(n uint32, s uint16) uint32 { return n >> s }},
+ {32, true, 8, true, func(n int32, s uint8) int32 { return n << s }},
+ {32, true, 8, false, func(n int32, s uint8) int32 { return n >> s }},
+ {32, false, 8, false, func(n uint32, s uint8) uint32 { return n >> s }},
+
+ {16, true, 64, true, func(n int16, s uint64) int16 { return n << s }},
+ {16, true, 64, false, func(n int16, s uint64) int16 { return n >> s }},
+ {16, false, 64, false, func(n uint16, s uint64) uint16 { return n >> s }},
+ {16, true, 32, true, func(n int16, s uint32) int16 { return n << s }},
+ {16, true, 32, false, func(n int16, s uint32) int16 { return n >> s }},
+ {16, false, 32, false, func(n uint16, s uint32) uint16 { return n >> s }},
+ {16, true, 16, true, func(n int16, s uint16) int16 { return n << s }},
+ {16, true, 16, false, func(n int16, s uint16) int16 { return n >> s }},
+ {16, false, 16, false, func(n uint16, s uint16) uint16 { return n >> s }},
+ {16, true, 8, true, func(n int16, s uint8) int16 { return n << s }},
+ {16, true, 8, false, func(n int16, s uint8) int16 { return n >> s }},
+ {16, false, 8, false, func(n uint16, s uint8) uint16 { return n >> s }},
+
+ {8, true, 64, true, func(n int8, s uint64) int8 { return n << s }},
+ {8, true, 64, false, func(n int8, s uint64) int8 { return n >> s }},
+ {8, false, 64, false, func(n uint8, s uint64) uint8 { return n >> s }},
+ {8, true, 32, true, func(n int8, s uint32) int8 { return n << s }},
+ {8, true, 32, false, func(n int8, s uint32) int8 { return n >> s }},
+ {8, false, 32, false, func(n uint8, s uint32) uint8 { return n >> s }},
+ {8, true, 16, true, func(n int8, s uint16) int8 { return n << s }},
+ {8, true, 16, false, func(n int8, s uint16) int8 { return n >> s }},
+ {8, false, 16, false, func(n uint8, s uint16) uint8 { return n >> s }},
+ {8, true, 8, true, func(n int8, s uint8) int8 { return n << s }},
+ {8, true, 8, false, func(n int8, s uint8) int8 { return n >> s }},
+ {8, false, 8, false, func(n uint8, s uint8) uint8 { return n >> s }},
+ } {
+ fv := reflect.ValueOf(test.f)
+ var args [2]reflect.Value
+ for i := 0; i < test.valueWidth; i++ {
+ // Build value to be shifted.
+ var n int64 = 1
+ for j := 0; j < i; j++ {
+ n <<= 1
+ }
+ args[0] = reflect.ValueOf(n).Convert(fv.Type().In(0))
+ for s := 0; s <= test.shiftWidth; s++ {
+ args[1] = reflect.ValueOf(s).Convert(fv.Type().In(1))
+
+ // Compute desired result. We're testing variable shifts
+ // assuming constant shifts are correct.
+ r := n
+ var op string
+ switch {
+ case test.left:
+ op = "<<"
+ for j := 0; j < s; j++ {
+ r <<= 1
+ }
+ switch test.valueWidth {
+ case 32:
+ r = int64(int32(r))
+ case 16:
+ r = int64(int16(r))
+ case 8:
+ r = int64(int8(r))
+ }
+ case test.signed:
+ op = ">>"
+ switch test.valueWidth {
+ case 32:
+ r = int64(int32(r))
+ case 16:
+ r = int64(int16(r))
+ case 8:
+ r = int64(int8(r))
+ }
+ for j := 0; j < s; j++ {
+ r >>= 1
+ }
+ default:
+ op = ">>>"
+ for j := 0; j < s; j++ {
+ r = int64(uint64(r) >> 1)
+ }
+ }
+
+ // Call function.
+ res := fv.Call(args[:])[0].Convert(reflect.ValueOf(r).Type())
+
+ if res.Int() != r {
+ t.Errorf("%s%dx%d(%x,%x)=%x, want %x", op, test.valueWidth, test.shiftWidth, n, s, res.Int(), r)
+ }
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
new file mode 100644
index 0000000..4d0837b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -0,0 +1,1172 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "fmt"
+)
+
+type InitEntry struct {
+ Xoffset int64 // struct, array only
+ Expr *Node // bytes of run-time computed expressions
+}
+
+type InitPlan struct {
+ E []InitEntry
+}
+
+// An InitSchedule is used to decompose assignment statements into
+// static and dynamic initialization parts. Static initializations are
+// handled by populating variables' linker symbol data, while dynamic
+// initializations are accumulated to be executed in order.
+type InitSchedule struct {
+ // out is the ordered list of dynamic initialization
+ // statements.
+ out []*Node
+
+ initplans map[*Node]*InitPlan
+ inittemps map[*Node]*Node
+}
+
+func (s *InitSchedule) append(n *Node) {
+ s.out = append(s.out, n)
+}
+
+// staticInit adds an initialization statement n to the schedule.
+func (s *InitSchedule) staticInit(n *Node) {
+ if !s.tryStaticInit(n) {
+ if Debug.P != 0 {
+ Dump("nonstatic", n)
+ }
+ s.append(n)
+ }
+}
+
+// tryStaticInit attempts to statically execute an initialization
+// statement and reports whether it succeeded.
+func (s *InitSchedule) tryStaticInit(n *Node) bool {
+ // Only worry about simple "l = r" assignments. Multiple
+ // variable/expression OAS2 assignments have already been
+ // replaced by multiple simple OAS assignments, and the other
+ // OAS2* assignments mostly necessitate dynamic execution
+ // anyway.
+ if n.Op != OAS {
+ return false
+ }
+ if n.Left.isBlank() && candiscard(n.Right) {
+ return true
+ }
+ lno := setlineno(n)
+ defer func() { lineno = lno }()
+ return s.staticassign(n.Left, n.Right)
+}
+
+// like staticassign but we are copying an already
+// initialized value r.
+func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
+ if r.Op != ONAME {
+ return false
+ }
+ if r.Class() == PFUNC {
+ pfuncsym(l, r)
+ return true
+ }
+ if r.Class() != PEXTERN || r.Sym.Pkg != localpkg {
+ return false
+ }
+ if r.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
+ return false
+ }
+ if r.Name.Defn.Op != OAS {
+ return false
+ }
+ if r.Type.IsString() { // perhaps overwritten by cmd/link -X (#34675)
+ return false
+ }
+ orig := r
+ r = r.Name.Defn.Right
+
+ for r.Op == OCONVNOP && !types.Identical(r.Type, l.Type) {
+ r = r.Left
+ }
+
+ switch r.Op {
+ case ONAME:
+ if s.staticcopy(l, r) {
+ return true
+ }
+ // We may have skipped past one or more OCONVNOPs, so
+ // use conv to ensure r is assignable to l (#13263).
+ s.append(nod(OAS, l, conv(r, l.Type)))
+ return true
+
+ case OLITERAL:
+ if isZero(r) {
+ return true
+ }
+ litsym(l, r, int(l.Type.Width))
+ return true
+
+ case OADDR:
+ if a := r.Left; a.Op == ONAME {
+ addrsym(l, a)
+ return true
+ }
+
+ case OPTRLIT:
+ switch r.Left.Op {
+ case OARRAYLIT, OSLICELIT, OSTRUCTLIT, OMAPLIT:
+ // copy pointer
+ addrsym(l, s.inittemps[r])
+ return true
+ }
+
+ case OSLICELIT:
+ // copy slice
+ a := s.inittemps[r]
+ slicesym(l, a, r.Right.Int64Val())
+ return true
+
+ case OARRAYLIT, OSTRUCTLIT:
+ p := s.initplans[r]
+
+ n := l.copy()
+ for i := range p.E {
+ e := &p.E[i]
+ n.Xoffset = l.Xoffset + e.Xoffset
+ n.Type = e.Expr.Type
+ if e.Expr.Op == OLITERAL {
+ litsym(n, e.Expr, int(n.Type.Width))
+ continue
+ }
+ ll := n.sepcopy()
+ if s.staticcopy(ll, e.Expr) {
+ continue
+ }
+ // Requires computation, but we're
+ // copying someone else's computation.
+ rr := orig.sepcopy()
+ rr.Type = ll.Type
+ rr.Xoffset += e.Xoffset
+ setlineno(rr)
+ s.append(nod(OAS, ll, rr))
+ }
+
+ return true
+ }
+
+ return false
+}
+
+func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
+ for r.Op == OCONVNOP {
+ r = r.Left
+ }
+
+ switch r.Op {
+ case ONAME:
+ return s.staticcopy(l, r)
+
+ case OLITERAL:
+ if isZero(r) {
+ return true
+ }
+ litsym(l, r, int(l.Type.Width))
+ return true
+
+ case OADDR:
+ var nam Node
+ if stataddr(&nam, r.Left) {
+ addrsym(l, &nam)
+ return true
+ }
+ fallthrough
+
+ case OPTRLIT:
+ switch r.Left.Op {
+ case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT:
+ // Init pointer.
+ a := staticname(r.Left.Type)
+
+ s.inittemps[r] = a
+ addrsym(l, a)
+
+ // Init underlying literal.
+ if !s.staticassign(a, r.Left) {
+ s.append(nod(OAS, a, r.Left))
+ }
+ return true
+ }
+ //dump("not static ptrlit", r);
+
+ case OSTR2BYTES:
+ if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
+ sval := r.Left.StringVal()
+ slicebytes(l, sval)
+ return true
+ }
+
+ case OSLICELIT:
+ s.initplan(r)
+ // Init slice.
+ bound := r.Right.Int64Val()
+ ta := types.NewArray(r.Type.Elem(), bound)
+ ta.SetNoalg(true)
+ a := staticname(ta)
+ s.inittemps[r] = a
+ slicesym(l, a, bound)
+ // Fall through to init underlying array.
+ l = a
+ fallthrough
+
+ case OARRAYLIT, OSTRUCTLIT:
+ s.initplan(r)
+
+ p := s.initplans[r]
+ n := l.copy()
+ for i := range p.E {
+ e := &p.E[i]
+ n.Xoffset = l.Xoffset + e.Xoffset
+ n.Type = e.Expr.Type
+ if e.Expr.Op == OLITERAL {
+ litsym(n, e.Expr, int(n.Type.Width))
+ continue
+ }
+ setlineno(e.Expr)
+ a := n.sepcopy()
+ if !s.staticassign(a, e.Expr) {
+ s.append(nod(OAS, a, e.Expr))
+ }
+ }
+
+ return true
+
+ case OMAPLIT:
+ break
+
+ case OCLOSURE:
+ if hasemptycvars(r) {
+ if Debug_closure > 0 {
+ Warnl(r.Pos, "closure converted to global")
+ }
+ // Closures with no captured variables are globals,
+ // so the assignment can be done at link time.
+ pfuncsym(l, r.Func.Closure.Func.Nname)
+ return true
+ }
+ 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)
+ }
+
+ markTypeUsedInInterface(val.Type, l.Sym.Linksym())
+
+ 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.copy()
+
+ // Emit itab, advance offset.
+ addrsym(n, itab.Left) // itab is an OADDR node
+ 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 := n.sepcopy()
+ if !s.staticassign(a, val) {
+ s.append(nod(OAS, a, val))
+ }
+ } else {
+ // Construct temp to hold val, write pointer to temp into n.
+ a := staticname(val.Type)
+ s.inittemps[val] = a
+ if !s.staticassign(a, val) {
+ s.append(nod(OAS, a, val))
+ }
+ addrsym(n, a)
+ }
+
+ 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
+)
+
+func (c initContext) String() string {
+ if c == inInitFunction {
+ return "inInitFunction"
+ }
+ return "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.
+
+var statuniqgen int // name generator for static temps
+
+// staticname returns a name backed by a (writable) static data symbol.
+// Use readonlystaticname for read-only node.
+func staticname(t *types.Type) *Node {
+ // Don't use lookupN; it interns the resulting string, but these are all unique.
+ n := newname(lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
+ statuniqgen++
+ addvar(n, t, PEXTERN)
+ return n
+}
+
+// readonlystaticname returns a name backed by a read-only static data symbol.
+func readonlystaticname(t *types.Type) *Node {
+ n := staticname(t)
+ n.MarkReadonly()
+ n.Sym.Linksym().Set(obj.AttrContentAddressable, true)
+ n.Sym.Linksym().Set(obj.AttrLocal, true)
+ return n
+}
+
+func (n *Node) isSimpleName() bool {
+ return n.Op == ONAME && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
+}
+
+func litas(l *Node, r *Node, init *Nodes) {
+ a := nod(OAS, l, r)
+ a = typecheck(a, ctxStmt)
+ a = walkexpr(a, init)
+ init.Append(a)
+}
+
+// initGenType is a bitmap indicating the types of generation that will occur for a static value.
+type initGenType uint8
+
+const (
+ initDynamic initGenType = 1 << iota // contains some dynamic values, for which init code will be generated
+ initConst // contains some constant values, which may be written into data symbols
+)
+
+// 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 n.isGoConst() {
+ return initConst
+ }
+ return initDynamic
+
+ case OSLICELIT:
+ if !top {
+ return initDynamic
+ }
+ if n.Right.Int64Val()/4 > int64(n.List.Len()) {
+ // <25% of entries have explicit values.
+ // Very rough estimation, it takes 4 bytes of instructions
+ // to initialize 1 byte of result. So don't use a static
+ // initializer if the dynamic initialization code would be
+ // smaller than the static value.
+ // See issue 23780.
+ return initDynamic
+ }
+
+ case OARRAYLIT, OSTRUCTLIT:
+ }
+
+ var mode initGenType
+ for _, n1 := range n.List.Slice() {
+ switch n1.Op {
+ case OKEY:
+ n1 = n1.Right
+ case OSTRUCTKEY:
+ n1 = n1.Left
+ }
+ mode |= getdyn(n1, false)
+ if mode == initDynamic|initConst {
+ break
+ }
+ }
+ return mode
+}
+
+// isStaticCompositeLiteral reports whether n is a compile-time constant.
+func isStaticCompositeLiteral(n *Node) bool {
+ switch n.Op {
+ case OSLICELIT:
+ return false
+ case OARRAYLIT:
+ 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
+ case OCONVIFACE:
+ // See staticassign's OCONVIFACE case for comments.
+ val := n
+ for val.Op == OCONVIFACE {
+ val = val.Left
+ }
+ if val.Type.IsInterface() {
+ return Isconst(val, CTNIL)
+ }
+ if isdirectiface(val.Type) && Isconst(val, CTNIL) {
+ return true
+ }
+ return isStaticCompositeLiteral(val)
+ }
+ return false
+}
+
+// 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 initialization 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
+
+const (
+ initKindStatic initKind = iota + 1
+ initKindDynamic
+ initKindLocalCode
+)
+
+// fixedlit handles struct, array, and slice literals.
+// TODO: expand documentation.
+func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes) {
+ isBlank := var_ == nblank
+ 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 = indexconst(r.Left)
+ if k < 0 {
+ Fatalf("fixedlit: invalid index %v", r.Left)
+ }
+ r = r.Right
+ }
+ a := nod(OINDEX, var_, nodintconst(k))
+ k++
+ if isBlank {
+ a = nblank
+ }
+ return a, r
+ }
+ case OSTRUCTLIT:
+ splitnode = func(r *Node) (*Node, *Node) {
+ if r.Op != OSTRUCTKEY {
+ Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
+ }
+ if r.Sym.IsBlank() || isBlank {
+ return nblank, r.Left
+ }
+ setlineno(r)
+ return nodSym(ODOT, var_, r.Sym), r.Left
+ }
+ default:
+ Fatalf("fixedlit bad op: %v", n.Op)
+ }
+
+ for _, r := range n.List.Slice() {
+ a, value := splitnode(r)
+ if a == nblank && candiscard(value) {
+ continue
+ }
+
+ switch value.Op {
+ case OSLICELIT:
+ if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
+ slicelit(ctxt, value, a, init)
+ continue
+ }
+
+ case OARRAYLIT, OSTRUCTLIT:
+ fixedlit(ctxt, kind, value, a, init)
+ continue
+ }
+
+ islit := value.isGoConst()
+ if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
+ continue
+ }
+
+ // build list of assignments: var[index] = expr
+ setlineno(a)
+ a = nod(OAS, a, value)
+ a = typecheck(a, ctxStmt)
+ switch kind {
+ case initKindStatic:
+ genAsStatic(a)
+ case initKindDynamic, initKindLocalCode:
+ a = orderStmtInPlace(a, map[string][]*Node{})
+ a = walkstmt(a)
+ init.Append(a)
+ default:
+ Fatalf("fixedlit: bad kind %d", kind)
+ }
+
+ }
+}
+
+func isSmallSliceLit(n *Node) bool {
+ if n.Op != OSLICELIT {
+ return false
+ }
+
+ r := n.Right
+
+ return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64Val() <= smallArrayBytes/n.Type.Elem().Width)
+}
+
+func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
+ // make an array type corresponding the number of elements we have
+ t := types.NewArray(n.Type.Elem(), n.Right.Int64Val())
+ dowidth(t)
+
+ if ctxt == inNonInitFunction {
+ // put everything into static array
+ vstat := staticname(t)
+
+ fixedlit(ctxt, initKindStatic, n, vstat, init)
+ fixedlit(ctxt, initKindDynamic, n, vstat, init)
+
+ // copy static to slice
+ var_ = typecheck(var_, ctxExpr|ctxAssign)
+ var nam Node
+ if !stataddr(&nam, var_) || nam.Class() != PEXTERN {
+ Fatalf("slicelit: %v", var_)
+ }
+ slicesym(&nam, vstat, t.NumElem())
+ return
+ }
+
+ // recipe for var = []t{...}
+ // 1. make a static array
+ // var vstat [...]t
+ // 2. assign (data statements) the constant part
+ // vstat = constpart{}
+ // 3. make an auto pointer to array and allocate heap to it
+ // var vauto *[...]t = new([...]t)
+ // 4. copy the static array to the auto array
+ // *vauto = vstat
+ // 5. for each dynamic part assign to the array
+ // vauto[i] = dynamic part
+ // 6. assign slice of allocated heap to var
+ // var = vauto[:]
+ //
+ // an optimization is done if there is no constant part
+ // 3. var vauto *[...]t = new([...]t)
+ // 5. vauto[i] = dynamic part
+ // 6. var = vauto[:]
+
+ // if the literal contains constants,
+ // make static initialized array (1),(2)
+ var vstat *Node
+
+ mode := getdyn(n, true)
+ if mode&initConst != 0 && !isSmallSliceLit(n) {
+ if ctxt == inInitFunction {
+ vstat = readonlystaticname(t)
+ } else {
+ vstat = staticname(t)
+ }
+ fixedlit(ctxt, initKindStatic, n, vstat, init)
+ }
+
+ // make new auto *array (3 declare)
+ vauto := temp(types.NewPtr(t))
+
+ // set auto to point at new temp or heap (3 assign)
+ var a *Node
+ if x := prealloc[n]; x != nil {
+ // temp allocated during order.go for dddarg
+ if !types.Identical(t, x.Type) {
+ panic("dotdotdot base type does not match order's assigned type")
+ }
+
+ if vstat == nil {
+ a = nod(OAS, x, nil)
+ a = typecheck(a, ctxStmt)
+ init.Append(a) // zero new temp
+ } else {
+ // Declare that we're about to initialize all of x.
+ // (Which happens at the *vauto = vstat below.)
+ init.Append(nod(OVARDEF, 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 = typecheck(a, ctxStmt)
+ init.Append(a) // zero new temp
+ a = a.Left
+ } else {
+ init.Append(nod(OVARDEF, a, nil))
+ }
+
+ a = nod(OADDR, a, nil)
+ } else {
+ a = nod(ONEW, nil, nil)
+ a.List.Set1(typenod(t))
+ }
+
+ a = nod(OAS, vauto, a)
+ a = typecheck(a, ctxStmt)
+ a = walkexpr(a, init)
+ init.Append(a)
+
+ if vstat != nil {
+ // copy static to heap (4)
+ a = nod(ODEREF, vauto, nil)
+
+ a = nod(OAS, a, vstat)
+ a = typecheck(a, ctxStmt)
+ a = walkexpr(a, init)
+ init.Append(a)
+ }
+
+ // put dynamics into array (5)
+ var index int64
+ for _, value := range n.List.Slice() {
+ if value.Op == OKEY {
+ index = indexconst(value.Left)
+ if index < 0 {
+ Fatalf("slicelit: invalid index %v", value.Left)
+ }
+ value = value.Right
+ }
+ a := nod(OINDEX, vauto, nodintconst(index))
+ a.SetBounded(true)
+ index++
+
+ // TODO need to check bounds?
+
+ switch value.Op {
+ case OSLICELIT:
+ break
+
+ case OARRAYLIT, OSTRUCTLIT:
+ k := initKindDynamic
+ if vstat == nil {
+ // Generate both static and dynamic initializations.
+ // See issue #31987.
+ k = initKindLocalCode
+ }
+ fixedlit(ctxt, k, value, a, init)
+ continue
+ }
+
+ if vstat != nil && value.isGoConst() { // already set by copy from static value
+ continue
+ }
+
+ // build list of vauto[c] = expr
+ setlineno(value)
+ a = nod(OAS, a, value)
+
+ a = typecheck(a, ctxStmt)
+ a = orderStmtInPlace(a, map[string][]*Node{})
+ a = walkstmt(a)
+ init.Append(a)
+ }
+
+ // make slice out of heap (6)
+ a = nod(OAS, var_, nod(OSLICE, vauto, nil))
+
+ a = typecheck(a, ctxStmt)
+ a = orderStmtInPlace(a, map[string][]*Node{})
+ a = walkstmt(a)
+ init.Append(a)
+}
+
+func maplit(n *Node, m *Node, init *Nodes) {
+ // make the map var
+ a := nod(OMAKE, nil, nil)
+ a.Esc = n.Esc
+ a.List.Set2(typenod(n.Type), nodintconst(int64(n.List.Len())))
+ litas(m, a, init)
+
+ entries := n.List.Slice()
+
+ // The order pass already removed any dynamic (runtime-computed) entries.
+ // All remaining entries are static. Double-check that.
+ for _, r := range entries {
+ if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
+ Fatalf("maplit: entry is not a literal: %v", r)
+ }
+ }
+
+ if len(entries) > 25 {
+ // For a large number of entries, put them in an array and loop.
+
+ // build types [count]Tindex and [count]Tvalue
+ tk := types.NewArray(n.Type.Key(), int64(len(entries)))
+ te := types.NewArray(n.Type.Elem(), int64(len(entries)))
+
+ tk.SetNoalg(true)
+ te.SetNoalg(true)
+
+ dowidth(tk)
+ dowidth(te)
+
+ // make and initialize static arrays
+ vstatk := readonlystaticname(tk)
+ vstate := readonlystaticname(te)
+
+ datak := nod(OARRAYLIT, nil, nil)
+ datae := nod(OARRAYLIT, nil, nil)
+ for _, r := range entries {
+ datak.List.Append(r.Left)
+ datae.List.Append(r.Right)
+ }
+ fixedlit(inInitFunction, initKindStatic, datak, vstatk, init)
+ fixedlit(inInitFunction, initKindStatic, datae, vstate, init)
+
+ // loop adding structure elements to map
+ // for i = 0; i < len(vstatk); i++ {
+ // map[vstatk[i]] = vstate[i]
+ // }
+ i := temp(types.Types[TINT])
+ rhs := nod(OINDEX, vstate, i)
+ rhs.SetBounded(true)
+
+ kidx := nod(OINDEX, vstatk, i)
+ kidx.SetBounded(true)
+ lhs := nod(OINDEX, m, kidx)
+
+ 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)
+
+ loop := nod(OFOR, cond, incr)
+ loop.Nbody.Set1(body)
+ loop.Ninit.Set1(zero)
+
+ loop = typecheck(loop, ctxStmt)
+ loop = walkstmt(loop)
+ init.Append(loop)
+ return
+ }
+ // For a small number of entries, just add them directly.
+
+ // Build list of var[c] = expr.
+ // Use temporaries so that mapassign1 can have addressable key, elem.
+ // TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys.
+ tmpkey := temp(m.Type.Key())
+ tmpelem := temp(m.Type.Elem())
+
+ for _, r := range entries {
+ index, elem := r.Left, r.Right
+
+ setlineno(index)
+ a := nod(OAS, tmpkey, index)
+ a = typecheck(a, ctxStmt)
+ a = walkstmt(a)
+ init.Append(a)
+
+ setlineno(elem)
+ a = nod(OAS, tmpelem, elem)
+ a = typecheck(a, ctxStmt)
+ a = walkstmt(a)
+ init.Append(a)
+
+ setlineno(tmpelem)
+ a = nod(OAS, nod(OINDEX, m, tmpkey), tmpelem)
+ a = typecheck(a, ctxStmt)
+ a = walkstmt(a)
+ init.Append(a)
+ }
+
+ a = nod(OVARKILL, tmpkey, nil)
+ a = typecheck(a, ctxStmt)
+ init.Append(a)
+ a = nod(OVARKILL, tmpelem, nil)
+ a = typecheck(a, ctxStmt)
+ init.Append(a)
+}
+
+func anylit(n *Node, var_ *Node, init *Nodes) {
+ t := n.Type
+ switch n.Op {
+ default:
+ Fatalf("anylit: not lit, op=%v node=%v", n.Op, n)
+
+ case ONAME:
+ a := nod(OAS, var_, n)
+ a = typecheck(a, ctxStmt)
+ init.Append(a)
+
+ case OPTRLIT:
+ if !t.IsPtr() {
+ Fatalf("anylit: not ptr")
+ }
+
+ var r *Node
+ if n.Right != nil {
+ // n.Right is stack temporary used as backing store.
+ init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410)
+ r = nod(OADDR, n.Right, nil)
+ r = typecheck(r, ctxExpr)
+ } else {
+ r = nod(ONEW, nil, nil)
+ r.SetTypecheck(1)
+ r.Type = t
+ r.Esc = n.Esc
+ }
+
+ r = walkexpr(r, init)
+ a := nod(OAS, var_, r)
+
+ a = typecheck(a, ctxStmt)
+ init.Append(a)
+
+ var_ = nod(ODEREF, var_, nil)
+ var_ = typecheck(var_, ctxExpr|ctxAssign)
+ anylit(n.Left, var_, init)
+
+ case OSTRUCTLIT, OARRAYLIT:
+ if !t.IsStruct() && !t.IsArray() {
+ Fatalf("anylit: not struct/array")
+ }
+
+ if var_.isSimpleName() && n.List.Len() > 4 {
+ // lay out static data
+ vstat := readonlystaticname(t)
+
+ ctxt := inInitFunction
+ if n.Op == OARRAYLIT {
+ ctxt = inNonInitFunction
+ }
+ fixedlit(ctxt, initKindStatic, n, vstat, init)
+
+ // copy static to var
+ a := nod(OAS, var_, vstat)
+
+ a = typecheck(a, ctxStmt)
+ a = walkexpr(a, init)
+ init.Append(a)
+
+ // add expressions to automatic
+ fixedlit(inInitFunction, initKindDynamic, n, var_, init)
+ break
+ }
+
+ var components int64
+ if n.Op == OARRAYLIT {
+ components = t.NumElem()
+ } else {
+ components = int64(t.NumFields())
+ }
+ // 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, ctxStmt)
+ a = walkexpr(a, init)
+ init.Append(a)
+ }
+
+ fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
+
+ case OSLICELIT:
+ slicelit(inInitFunction, n, var_, init)
+
+ case OMAPLIT:
+ if !t.IsMap() {
+ Fatalf("anylit: not map")
+ }
+ maplit(n, var_, init)
+ }
+}
+
+func oaslit(n *Node, init *Nodes) bool {
+ if n.Left == nil || n.Right == nil {
+ // not a special composite literal assignment
+ return false
+ }
+ if n.Left.Type == nil || n.Right.Type == nil {
+ // not a special composite literal assignment
+ return false
+ }
+ if !n.Left.isSimpleName() {
+ // not a special composite literal assignment
+ return false
+ }
+ if !types.Identical(n.Left.Type, n.Right.Type) {
+ // not a special composite literal assignment
+ return false
+ }
+
+ switch n.Right.Op {
+ default:
+ // not a special composite literal assignment
+ return false
+
+ case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
+ if vmatch1(n.Left, n.Right) {
+ // not a special composite literal assignment
+ return false
+ }
+ anylit(n.Right, n.Left, init)
+ }
+
+ n.Op = OEMPTY
+ n.Right = nil
+ return true
+}
+
+func getlit(lit *Node) int {
+ if smallintconst(lit) {
+ return int(lit.Int64Val())
+ }
+ return -1
+}
+
+// stataddr sets nam to the static address of n and reports whether it succeeded.
+func stataddr(nam *Node, n *Node) bool {
+ if n == nil {
+ return false
+ }
+
+ switch n.Op {
+ case ONAME:
+ *nam = *n
+ return true
+
+ case ODOT:
+ if !stataddr(nam, n.Left) {
+ break
+ }
+ nam.Xoffset += n.Xoffset
+ nam.Type = n.Type
+ return true
+
+ case OINDEX:
+ if n.Left.Type.IsSlice() {
+ break
+ }
+ if !stataddr(nam, n.Left) {
+ break
+ }
+ l := getlit(n.Right)
+ if l < 0 {
+ break
+ }
+
+ // Check for overflow.
+ if n.Type.Width != 0 && thearch.MAXWIDTH/n.Type.Width <= int64(l) {
+ break
+ }
+ nam.Xoffset += int64(l) * n.Type.Width
+ nam.Type = n.Type
+ return true
+ }
+
+ return false
+}
+
+func (s *InitSchedule) initplan(n *Node) {
+ if s.initplans[n] != nil {
+ return
+ }
+ p := new(InitPlan)
+ s.initplans[n] = p
+ switch n.Op {
+ default:
+ Fatalf("initplan")
+
+ case OARRAYLIT, OSLICELIT:
+ var k int64
+ for _, a := range n.List.Slice() {
+ if a.Op == OKEY {
+ k = indexconst(a.Left)
+ if k < 0 {
+ Fatalf("initplan arraylit: invalid index %v", a.Left)
+ }
+ a = a.Right
+ }
+ s.addvalue(p, k*n.Type.Elem().Width, a)
+ k++
+ }
+
+ case OSTRUCTLIT:
+ for _, a := range n.List.Slice() {
+ if a.Op != OSTRUCTKEY {
+ Fatalf("initplan structlit")
+ }
+ if a.Sym.IsBlank() {
+ continue
+ }
+ s.addvalue(p, a.Xoffset, a.Left)
+ }
+
+ case OMAPLIT:
+ for _, a := range n.List.Slice() {
+ if a.Op != OKEY {
+ Fatalf("initplan maplit")
+ }
+ s.addvalue(p, -1, a.Right)
+ }
+ }
+}
+
+func (s *InitSchedule) addvalue(p *InitPlan, xoffset int64, n *Node) {
+ // special case: zero can be dropped entirely
+ if isZero(n) {
+ return
+ }
+
+ // special case: inline struct and array (not slice) literals
+ if isvaluelit(n) {
+ s.initplan(n)
+ q := s.initplans[n]
+ for _, qe := range q.E {
+ // qe is a copy; we are not modifying entries in q.E
+ qe.Xoffset += xoffset
+ p.E = append(p.E, qe)
+ }
+ return
+ }
+
+ // add to plan
+ p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n})
+}
+
+func isZero(n *Node) bool {
+ switch n.Op {
+ case OLITERAL:
+ switch u := n.Val().U.(type) {
+ default:
+ Dump("unexpected literal", n)
+ Fatalf("isZero")
+ case *NilVal:
+ return true
+ case string:
+ return u == ""
+ case bool:
+ return !u
+ case *Mpint:
+ return u.CmpInt64(0) == 0
+ case *Mpflt:
+ return u.CmpFloat64(0) == 0
+ case *Mpcplx:
+ return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0
+ }
+
+ case OARRAYLIT:
+ for _, n1 := range n.List.Slice() {
+ if n1.Op == OKEY {
+ n1 = n1.Right
+ }
+ if !isZero(n1) {
+ return false
+ }
+ }
+ return true
+
+ case OSTRUCTLIT:
+ for _, n1 := range n.List.Slice() {
+ if !isZero(n1.Left) {
+ return false
+ }
+ }
+ return true
+ }
+
+ return false
+}
+
+func isvaluelit(n *Node) bool {
+ return n.Op == OARRAYLIT || n.Op == OSTRUCTLIT
+}
+
+func genAsStatic(as *Node) {
+ if as.Left.Type == nil {
+ Fatalf("genAsStatic as.Left not typechecked")
+ }
+
+ var nam Node
+ if !stataddr(&nam, as.Left) || (nam.Class() != PEXTERN && as.Left != nblank) {
+ Fatalf("genAsStatic: lhs %v", as.Left)
+ }
+
+ switch {
+ case as.Right.Op == OLITERAL:
+ litsym(&nam, as.Right, int(as.Right.Type.Width))
+ case as.Right.Op == ONAME && as.Right.Class() == PFUNC:
+ pfuncsym(&nam, as.Right)
+ default:
+ Fatalf("genAsStatic: rhs %v", as.Right)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/sizeof_test.go b/src/cmd/compile/internal/gc/sizeof_test.go
new file mode 100644
index 0000000..ce4a216
--- /dev/null
+++ b/src/cmd/compile/internal/gc/sizeof_test.go
@@ -0,0 +1,39 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "reflect"
+ "testing"
+ "unsafe"
+)
+
+// Assert that the size of important structures do not change unexpectedly.
+
+func TestSizeof(t *testing.T) {
+ const _64bit = unsafe.Sizeof(uintptr(0)) == 8
+
+ var tests = []struct {
+ val interface{} // type as a value
+ _32bit uintptr // size on 32bit platforms
+ _64bit uintptr // size on 64bit platforms
+ }{
+ {Func{}, 124, 224},
+ {Name{}, 32, 56},
+ {Param{}, 24, 48},
+ {Node{}, 76, 128},
+ }
+
+ for _, tt := range tests {
+ want := tt._32bit
+ if _64bit {
+ want = tt._64bit
+ }
+ got := reflect.TypeOf(tt.val).Size()
+ if want != got {
+ t.Errorf("unsafe.Sizeof(%T) = %d, want %d", tt.val, got, want)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
new file mode 100644
index 0000000..5b74754
--- /dev/null
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -0,0 +1,7231 @@
+// Copyright 2015 The Go Authors. 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 (
+ "encoding/binary"
+ "fmt"
+ "html"
+ "os"
+ "path/filepath"
+ "sort"
+
+ "bufio"
+ "bytes"
+ "cmd/compile/internal/ssa"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/obj/x86"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+ "cmd/internal/sys"
+)
+
+var ssaConfig *ssa.Config
+var ssaCaches []ssa.Cache
+
+var ssaDump string // early copy of $GOSSAFUNC; the func name to dump output for
+var ssaDir string // optional destination for ssa dump file
+var ssaDumpStdout bool // whether to dump to stdout
+var ssaDumpCFG string // generate CFGs for these phases
+const ssaDumpFile = "ssa.html"
+
+// The max number of defers in a function using open-coded defers. We enforce this
+// limit because the deferBits bitmask is currently a single byte (to minimize code size)
+const maxOpenDefers = 8
+
+// ssaDumpInlined holds all inlined functions when ssaDump contains a function name.
+var ssaDumpInlined []*Node
+
+func initssaconfig() {
+ types_ := ssa.NewTypes()
+
+ if thearch.SoftFloat {
+ softfloatInit()
+ }
+
+ // Generate a few pointer types that are uncommon in the frontend but common in the backend.
+ // Caching is disabled in the backend, so generating these here avoids allocations.
+ _ = types.NewPtr(types.Types[TINTER]) // *interface{}
+ _ = types.NewPtr(types.NewPtr(types.Types[TSTRING])) // **string
+ _ = types.NewPtr(types.NewSlice(types.Types[TINTER])) // *[]interface{}
+ _ = types.NewPtr(types.NewPtr(types.Bytetype)) // **byte
+ _ = types.NewPtr(types.NewSlice(types.Bytetype)) // *[]byte
+ _ = types.NewPtr(types.NewSlice(types.Types[TSTRING])) // *[]string
+ _ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[TUINT8]))) // ***uint8
+ _ = types.NewPtr(types.Types[TINT16]) // *int16
+ _ = types.NewPtr(types.Types[TINT64]) // *int64
+ _ = types.NewPtr(types.Errortype) // *error
+ types.NewPtrCacheEnabled = false
+ ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug.N == 0)
+ ssaConfig.SoftFloat = thearch.SoftFloat
+ ssaConfig.Race = flag_race
+ ssaCaches = make([]ssa.Cache, nBackendWorkers)
+
+ // Set up some runtime functions we'll need to call.
+ assertE2I = sysfunc("assertE2I")
+ assertE2I2 = sysfunc("assertE2I2")
+ assertI2I = sysfunc("assertI2I")
+ assertI2I2 = sysfunc("assertI2I2")
+ deferproc = sysfunc("deferproc")
+ deferprocStack = sysfunc("deferprocStack")
+ Deferreturn = sysfunc("deferreturn")
+ Duffcopy = sysfunc("duffcopy")
+ Duffzero = sysfunc("duffzero")
+ gcWriteBarrier = sysfunc("gcWriteBarrier")
+ goschedguarded = sysfunc("goschedguarded")
+ growslice = sysfunc("growslice")
+ msanread = sysfunc("msanread")
+ msanwrite = sysfunc("msanwrite")
+ msanmove = sysfunc("msanmove")
+ newobject = sysfunc("newobject")
+ newproc = sysfunc("newproc")
+ panicdivide = sysfunc("panicdivide")
+ panicdottypeE = sysfunc("panicdottypeE")
+ panicdottypeI = sysfunc("panicdottypeI")
+ panicnildottype = sysfunc("panicnildottype")
+ panicoverflow = sysfunc("panicoverflow")
+ panicshift = sysfunc("panicshift")
+ raceread = sysfunc("raceread")
+ racereadrange = sysfunc("racereadrange")
+ racewrite = sysfunc("racewrite")
+ racewriterange = sysfunc("racewriterange")
+ x86HasPOPCNT = sysvar("x86HasPOPCNT") // bool
+ x86HasSSE41 = sysvar("x86HasSSE41") // bool
+ x86HasFMA = sysvar("x86HasFMA") // bool
+ armHasVFPv4 = sysvar("armHasVFPv4") // bool
+ arm64HasATOMICS = sysvar("arm64HasATOMICS") // bool
+ typedmemclr = sysfunc("typedmemclr")
+ typedmemmove = sysfunc("typedmemmove")
+ Udiv = sysvar("udiv") // asm func with special ABI
+ writeBarrier = sysvar("writeBarrier") // struct { bool; ... }
+ zerobaseSym = sysvar("zerobase")
+
+ // asm funcs with special ABI
+ if thearch.LinkArch.Name == "amd64" {
+ GCWriteBarrierReg = map[int16]*obj.LSym{
+ x86.REG_AX: sysfunc("gcWriteBarrier"),
+ x86.REG_CX: sysfunc("gcWriteBarrierCX"),
+ x86.REG_DX: sysfunc("gcWriteBarrierDX"),
+ x86.REG_BX: sysfunc("gcWriteBarrierBX"),
+ x86.REG_BP: sysfunc("gcWriteBarrierBP"),
+ x86.REG_SI: sysfunc("gcWriteBarrierSI"),
+ x86.REG_R8: sysfunc("gcWriteBarrierR8"),
+ x86.REG_R9: sysfunc("gcWriteBarrierR9"),
+ }
+ }
+
+ if thearch.LinkArch.Family == sys.Wasm {
+ BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("goPanicIndex")
+ BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("goPanicIndexU")
+ BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("goPanicSliceAlen")
+ BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("goPanicSliceAlenU")
+ BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("goPanicSliceAcap")
+ BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("goPanicSliceAcapU")
+ BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("goPanicSliceB")
+ BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("goPanicSliceBU")
+ BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("goPanicSlice3Alen")
+ BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("goPanicSlice3AlenU")
+ BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("goPanicSlice3Acap")
+ BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("goPanicSlice3AcapU")
+ BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("goPanicSlice3B")
+ BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("goPanicSlice3BU")
+ BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("goPanicSlice3C")
+ BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("goPanicSlice3CU")
+ } else {
+ BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("panicIndex")
+ BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("panicIndexU")
+ BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("panicSliceAlen")
+ BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("panicSliceAlenU")
+ BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("panicSliceAcap")
+ BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("panicSliceAcapU")
+ BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("panicSliceB")
+ BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("panicSliceBU")
+ BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("panicSlice3Alen")
+ BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("panicSlice3AlenU")
+ BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("panicSlice3Acap")
+ BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("panicSlice3AcapU")
+ BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("panicSlice3B")
+ BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("panicSlice3BU")
+ BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("panicSlice3C")
+ BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("panicSlice3CU")
+ }
+ if thearch.LinkArch.PtrSize == 4 {
+ ExtendCheckFunc[ssa.BoundsIndex] = sysvar("panicExtendIndex")
+ ExtendCheckFunc[ssa.BoundsIndexU] = sysvar("panicExtendIndexU")
+ ExtendCheckFunc[ssa.BoundsSliceAlen] = sysvar("panicExtendSliceAlen")
+ ExtendCheckFunc[ssa.BoundsSliceAlenU] = sysvar("panicExtendSliceAlenU")
+ ExtendCheckFunc[ssa.BoundsSliceAcap] = sysvar("panicExtendSliceAcap")
+ ExtendCheckFunc[ssa.BoundsSliceAcapU] = sysvar("panicExtendSliceAcapU")
+ ExtendCheckFunc[ssa.BoundsSliceB] = sysvar("panicExtendSliceB")
+ ExtendCheckFunc[ssa.BoundsSliceBU] = sysvar("panicExtendSliceBU")
+ ExtendCheckFunc[ssa.BoundsSlice3Alen] = sysvar("panicExtendSlice3Alen")
+ ExtendCheckFunc[ssa.BoundsSlice3AlenU] = sysvar("panicExtendSlice3AlenU")
+ ExtendCheckFunc[ssa.BoundsSlice3Acap] = sysvar("panicExtendSlice3Acap")
+ ExtendCheckFunc[ssa.BoundsSlice3AcapU] = sysvar("panicExtendSlice3AcapU")
+ ExtendCheckFunc[ssa.BoundsSlice3B] = sysvar("panicExtendSlice3B")
+ ExtendCheckFunc[ssa.BoundsSlice3BU] = sysvar("panicExtendSlice3BU")
+ ExtendCheckFunc[ssa.BoundsSlice3C] = sysvar("panicExtendSlice3C")
+ ExtendCheckFunc[ssa.BoundsSlice3CU] = sysvar("panicExtendSlice3CU")
+ }
+
+ // Wasm (all asm funcs with special ABIs)
+ WasmMove = sysvar("wasmMove")
+ WasmZero = sysvar("wasmZero")
+ WasmDiv = sysvar("wasmDiv")
+ WasmTruncS = sysvar("wasmTruncS")
+ WasmTruncU = sysvar("wasmTruncU")
+ SigPanic = sysfunc("sigpanic")
+}
+
+// getParam returns the Field of ith param of node n (which is a
+// function/method/interface call), where the receiver of a method call is
+// considered as the 0th parameter. This does not include the receiver of an
+// interface call.
+func getParam(n *Node, i int) *types.Field {
+ t := n.Left.Type
+ if n.Op == OCALLMETH {
+ if i == 0 {
+ return t.Recv()
+ }
+ return t.Params().Field(i - 1)
+ }
+ return t.Params().Field(i)
+}
+
+// dvarint writes a varint v to the funcdata in symbol x and returns the new offset
+func dvarint(x *obj.LSym, off int, v int64) int {
+ if v < 0 || v > 1e9 {
+ panic(fmt.Sprintf("dvarint: bad offset for funcdata - %v", v))
+ }
+ if v < 1<<7 {
+ return duint8(x, off, uint8(v))
+ }
+ off = duint8(x, off, uint8((v&127)|128))
+ if v < 1<<14 {
+ return duint8(x, off, uint8(v>>7))
+ }
+ off = duint8(x, off, uint8(((v>>7)&127)|128))
+ if v < 1<<21 {
+ return duint8(x, off, uint8(v>>14))
+ }
+ off = duint8(x, off, uint8(((v>>14)&127)|128))
+ if v < 1<<28 {
+ return duint8(x, off, uint8(v>>21))
+ }
+ off = duint8(x, off, uint8(((v>>21)&127)|128))
+ return duint8(x, off, uint8(v>>28))
+}
+
+// emitOpenDeferInfo emits FUNCDATA information about the defers in a function
+// that is using open-coded defers. This funcdata is used to determine the active
+// defers in a function and execute those defers during panic processing.
+//
+// The funcdata is all encoded in varints (since values will almost always be less than
+// 128, but stack offsets could potentially be up to 2Gbyte). All "locations" (offsets)
+// for stack variables are specified as the number of bytes below varp (pointer to the
+// top of the local variables) for their starting address. The format is:
+//
+// - Max total argument size among all the defers
+// - Offset of the deferBits variable
+// - Number of defers in the function
+// - Information about each defer call, in reverse order of appearance in the function:
+// - Total argument size of the call
+// - Offset of the closure value to call
+// - Number of arguments (including interface receiver or method receiver as first arg)
+// - Information about each argument
+// - Offset of the stored defer argument in this function's frame
+// - Size of the argument
+// - Offset of where argument should be placed in the args frame when making call
+func (s *state) emitOpenDeferInfo() {
+ x := Ctxt.Lookup(s.curfn.Func.lsym.Name + ".opendefer")
+ s.curfn.Func.lsym.Func().OpenCodedDeferInfo = x
+ off := 0
+
+ // Compute maxargsize (max size of arguments for all defers)
+ // first, so we can output it first to the funcdata
+ var maxargsize int64
+ for i := len(s.openDefers) - 1; i >= 0; i-- {
+ r := s.openDefers[i]
+ argsize := r.n.Left.Type.ArgWidth()
+ if argsize > maxargsize {
+ maxargsize = argsize
+ }
+ }
+ off = dvarint(x, off, maxargsize)
+ off = dvarint(x, off, -s.deferBitsTemp.Xoffset)
+ off = dvarint(x, off, int64(len(s.openDefers)))
+
+ // Write in reverse-order, for ease of running in that order at runtime
+ for i := len(s.openDefers) - 1; i >= 0; i-- {
+ r := s.openDefers[i]
+ off = dvarint(x, off, r.n.Left.Type.ArgWidth())
+ off = dvarint(x, off, -r.closureNode.Xoffset)
+ numArgs := len(r.argNodes)
+ if r.rcvrNode != nil {
+ // If there's an interface receiver, treat/place it as the first
+ // arg. (If there is a method receiver, it's already included as
+ // first arg in r.argNodes.)
+ numArgs++
+ }
+ off = dvarint(x, off, int64(numArgs))
+ if r.rcvrNode != nil {
+ off = dvarint(x, off, -r.rcvrNode.Xoffset)
+ off = dvarint(x, off, s.config.PtrSize)
+ off = dvarint(x, off, 0)
+ }
+ for j, arg := range r.argNodes {
+ f := getParam(r.n, j)
+ off = dvarint(x, off, -arg.Xoffset)
+ off = dvarint(x, off, f.Type.Size())
+ off = dvarint(x, off, f.Offset)
+ }
+ }
+}
+
+// buildssa builds an SSA function for fn.
+// worker indicates which of the backend workers is doing the processing.
+func buildssa(fn *Node, worker int) *ssa.Func {
+ name := fn.funcname()
+ printssa := false
+ if ssaDump != "" { // match either a simple name e.g. "(*Reader).Reset", or a package.name e.g. "compress/gzip.(*Reader).Reset"
+ printssa = name == ssaDump || myimportpath+"."+name == ssaDump
+ }
+ var astBuf *bytes.Buffer
+ if printssa {
+ astBuf = &bytes.Buffer{}
+ fdumplist(astBuf, "buildssa-enter", fn.Func.Enter)
+ fdumplist(astBuf, "buildssa-body", fn.Nbody)
+ fdumplist(astBuf, "buildssa-exit", fn.Func.Exit)
+ if ssaDumpStdout {
+ fmt.Println("generating SSA for", name)
+ fmt.Print(astBuf.String())
+ }
+ }
+
+ var s state
+ s.pushLine(fn.Pos)
+ defer s.popLine()
+
+ s.hasdefer = fn.Func.HasDefer()
+ if fn.Func.Pragma&CgoUnsafeArgs != 0 {
+ s.cgoUnsafeArgs = true
+ }
+
+ fe := ssafn{
+ curfn: fn,
+ log: printssa && ssaDumpStdout,
+ }
+ s.curfn = fn
+
+ s.f = ssa.NewFunc(&fe)
+ s.config = ssaConfig
+ s.f.Type = fn.Type
+ s.f.Config = ssaConfig
+ s.f.Cache = &ssaCaches[worker]
+ s.f.Cache.Reset()
+ s.f.Name = name
+ s.f.DebugTest = s.f.DebugHashMatch("GOSSAHASH")
+ s.f.PrintOrHtmlSSA = printssa
+ if fn.Func.Pragma&Nosplit != 0 {
+ s.f.NoSplit = true
+ }
+ s.panics = map[funcLine]*ssa.Block{}
+ s.softFloat = s.config.SoftFloat
+
+ // Allocate starting block
+ s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
+ s.f.Entry.Pos = fn.Pos
+
+ if printssa {
+ ssaDF := ssaDumpFile
+ if ssaDir != "" {
+ ssaDF = filepath.Join(ssaDir, myimportpath+"."+name+".html")
+ ssaD := filepath.Dir(ssaDF)
+ os.MkdirAll(ssaD, 0755)
+ }
+ s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG)
+ // TODO: generate and print a mapping from nodes to values and blocks
+ dumpSourcesColumn(s.f.HTMLWriter, fn)
+ s.f.HTMLWriter.WriteAST("AST", astBuf)
+ }
+
+ // 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, types.TypeMem)
+
+ s.hasOpenDefers = Debug.N == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
+ switch {
+ case s.hasOpenDefers && (Ctxt.Flag_shared || Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386":
+ // Don't support open-coded defers for 386 ONLY when using shared
+ // libraries, because there is extra code (added by rewriteToUseGot())
+ // preceding the deferreturn/ret code that is generated by gencallret()
+ // that we don't track correctly.
+ s.hasOpenDefers = false
+ }
+ if s.hasOpenDefers && s.curfn.Func.Exit.Len() > 0 {
+ // Skip doing open defers if there is any extra exit code (likely
+ // copying heap-allocated return values or race detection), since
+ // we will not generate that code in the case of the extra
+ // deferreturn/ret segment.
+ s.hasOpenDefers = false
+ }
+ if s.hasOpenDefers &&
+ s.curfn.Func.numReturns*s.curfn.Func.numDefers > 15 {
+ // Since we are generating defer calls at every exit for
+ // open-coded defers, skip doing open-coded defers if there are
+ // too many returns (especially if there are multiple defers).
+ // Open-coded defers are most important for improving performance
+ // for smaller functions (which don't have many returns).
+ s.hasOpenDefers = false
+ }
+
+ s.sp = s.entryNewValue0(ssa.OpSP, types.Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
+ s.sb = s.entryNewValue0(ssa.OpSB, types.Types[TUINTPTR])
+
+ s.startBlock(s.f.Entry)
+ s.vars[&memVar] = s.startmem
+ if s.hasOpenDefers {
+ // Create the deferBits variable and stack slot. deferBits is a
+ // bitmask showing which of the open-coded defers in this function
+ // have been activated.
+ deferBitsTemp := tempAt(src.NoXPos, s.curfn, types.Types[TUINT8])
+ s.deferBitsTemp = deferBitsTemp
+ // For this value, AuxInt is initialized to zero by default
+ startDeferBits := s.entryNewValue0(ssa.OpConst8, types.Types[TUINT8])
+ s.vars[&deferBitsVar] = startDeferBits
+ s.deferBitsAddr = s.addr(deferBitsTemp)
+ s.store(types.Types[TUINT8], s.deferBitsAddr, startDeferBits)
+ // Make sure that the deferBits stack slot is kept alive (for use
+ // by panics) and stores to deferBits are not eliminated, even if
+ // all checking code on deferBits in the function exit can be
+ // eliminated, because the defer statements were all
+ // unconditional.
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, deferBitsTemp, s.mem(), false)
+ }
+
+ // Generate addresses of local declarations
+ s.decladdrs = map[*Node]*ssa.Value{}
+ var args []ssa.Param
+ var results []ssa.Param
+ for _, n := range fn.Func.Dcl {
+ switch n.Class() {
+ case PPARAM:
+ s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
+ args = append(args, ssa.Param{Type: n.Type, Offset: int32(n.Xoffset)})
+ case PPARAMOUT:
+ s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
+ results = append(results, ssa.Param{Type: n.Type, Offset: int32(n.Xoffset)})
+ if 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)
+ }
+ case PAUTO:
+ // processed at each use, to prevent Addr coming
+ // before the decl.
+ case PAUTOHEAP:
+ // moved to heap - already handled by frontend
+ case PFUNC:
+ // local function - already handled by frontend
+ default:
+ s.Fatalf("local variable with class %v unimplemented", n.Class())
+ }
+ }
+
+ // Populate SSAable arguments.
+ for _, n := range fn.Func.Dcl {
+ if n.Class() == PPARAM && s.canSSA(n) {
+ v := s.newValue0A(ssa.OpArg, n.Type, n)
+ s.vars[n] = v
+ s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself.
+ }
+ }
+
+ // Convert the AST-based IR to the SSA-based IR
+ s.stmtList(fn.Func.Enter)
+ s.stmtList(fn.Nbody)
+
+ // fallthrough to exit
+ if s.curBlock != nil {
+ s.pushLine(fn.Func.Endlineno)
+ s.exit()
+ s.popLine()
+ }
+
+ for _, b := range s.f.Blocks {
+ if b.Pos != src.NoXPos {
+ s.updateUnsetPredPos(b)
+ }
+ }
+
+ s.insertPhis()
+
+ // Main call to ssa package to compile function
+ ssa.Compile(s.f)
+
+ if s.hasOpenDefers {
+ s.emitOpenDeferInfo()
+ }
+
+ return s.f
+}
+
+func dumpSourcesColumn(writer *ssa.HTMLWriter, fn *Node) {
+ // Read sources of target function fn.
+ fname := Ctxt.PosTable.Pos(fn.Pos).Filename()
+ targetFn, err := readFuncLines(fname, fn.Pos.Line(), fn.Func.Endlineno.Line())
+ if err != nil {
+ writer.Logf("cannot read sources for function %v: %v", fn, err)
+ }
+
+ // Read sources of inlined functions.
+ var inlFns []*ssa.FuncLines
+ for _, fi := range ssaDumpInlined {
+ var elno src.XPos
+ if fi.Name.Defn == nil {
+ // Endlineno is filled from exported data.
+ elno = fi.Func.Endlineno
+ } else {
+ elno = fi.Name.Defn.Func.Endlineno
+ }
+ fname := Ctxt.PosTable.Pos(fi.Pos).Filename()
+ fnLines, err := readFuncLines(fname, fi.Pos.Line(), elno.Line())
+ if err != nil {
+ writer.Logf("cannot read sources for inlined function %v: %v", fi, err)
+ continue
+ }
+ inlFns = append(inlFns, fnLines)
+ }
+
+ sort.Sort(ssa.ByTopo(inlFns))
+ if targetFn != nil {
+ inlFns = append([]*ssa.FuncLines{targetFn}, inlFns...)
+ }
+
+ writer.WriteSources("sources", inlFns)
+}
+
+func readFuncLines(file string, start, end uint) (*ssa.FuncLines, error) {
+ f, err := os.Open(os.ExpandEnv(file))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ var lines []string
+ ln := uint(1)
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() && ln <= end {
+ if ln >= start {
+ lines = append(lines, scanner.Text())
+ }
+ ln++
+ }
+ return &ssa.FuncLines{Filename: file, StartLineno: start, Lines: lines}, nil
+}
+
+// updateUnsetPredPos propagates the earliest-value position information for b
+// towards all of b's predecessors that need a position, and recurs on that
+// predecessor if its position is updated. B should have a non-empty position.
+func (s *state) updateUnsetPredPos(b *ssa.Block) {
+ if b.Pos == src.NoXPos {
+ s.Fatalf("Block %s should have a position", b)
+ }
+ bestPos := src.NoXPos
+ for _, e := range b.Preds {
+ p := e.Block()
+ if !p.LackingPos() {
+ continue
+ }
+ if bestPos == src.NoXPos {
+ bestPos = b.Pos
+ for _, v := range b.Values {
+ if v.LackingPos() {
+ continue
+ }
+ if v.Pos != src.NoXPos {
+ // Assume values are still in roughly textual order;
+ // TODO: could also seek minimum position?
+ bestPos = v.Pos
+ break
+ }
+ }
+ }
+ p.Pos = bestPos
+ s.updateUnsetPredPos(p) // We do not expect long chains of these, thus recursion is okay.
+ }
+}
+
+// Information about each open-coded defer.
+type openDeferInfo struct {
+ // The ODEFER node representing the function call of the defer
+ n *Node
+ // If defer call is closure call, the address of the argtmp where the
+ // closure is stored.
+ closure *ssa.Value
+ // The node representing the argtmp where the closure is stored - used for
+ // function, method, or interface call, to store a closure that panic
+ // processing can use for this defer.
+ closureNode *Node
+ // If defer call is interface call, the address of the argtmp where the
+ // receiver is stored
+ rcvr *ssa.Value
+ // The node representing the argtmp where the receiver is stored
+ rcvrNode *Node
+ // The addresses of the argtmps where the evaluated arguments of the defer
+ // function call are stored.
+ argVals []*ssa.Value
+ // The nodes representing the argtmps where the args of the defer are stored
+ argNodes []*Node
+}
+
+type state struct {
+ // configuration (arch) information
+ config *ssa.Config
+
+ // function we're building
+ f *ssa.Func
+
+ // Node for function
+ curfn *Node
+
+ // labels and labeled control flow nodes (OFOR, OFORUNTIL, OSWITCH, OSELECT) in f
+ labels map[string]*ssaLabel
+ labeledNodes map[*Node]*ssaLabel
+
+ // unlabeled break and continue statement tracking
+ breakTo *ssa.Block // current target for plain break statement
+ continueTo *ssa.Block // current target for plain continue statement
+
+ // current location where we're interpreting the AST
+ curBlock *ssa.Block
+
+ // variable assignments in the current block (map from variable symbol to ssa value)
+ // *Node is the unique identifier (an ONAME Node) for the variable.
+ // 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
+
+ // addresses of PPARAM and PPARAMOUT variables.
+ decladdrs map[*Node]*ssa.Value
+
+ // starting values. Memory, stack pointer, and globals pointer
+ startmem *ssa.Value
+ sp *ssa.Value
+ sb *ssa.Value
+ // value representing address of where deferBits autotmp is stored
+ deferBitsAddr *ssa.Value
+ deferBitsTemp *Node
+
+ // line number stack. The current line number is top of stack
+ line []src.XPos
+ // the last line number processed; it may have been popped
+ lastPos src.XPos
+
+ // list of panic calls by function name and line number.
+ // Used to deduplicate panic calls.
+ panics map[funcLine]*ssa.Block
+
+ // list of PPARAMOUT (return) variables.
+ returns []*Node
+
+ cgoUnsafeArgs bool
+ hasdefer bool // whether the function contains a defer statement
+ softFloat bool
+ hasOpenDefers bool // whether we are doing open-coded defers
+
+ // If doing open-coded defers, list of info about the defer calls in
+ // scanning order. Hence, at exit we should run these defers in reverse
+ // order of this list
+ openDefers []*openDeferInfo
+ // For open-coded defers, this is the beginning and end blocks of the last
+ // defer exit code that we have generated so far. We use these to share
+ // code between exits if the shareDeferExits option (disabled by default)
+ // is on.
+ lastDeferExit *ssa.Block // Entry block of last defer exit code we generated
+ lastDeferFinalBlock *ssa.Block // Final block of last defer exit code we generated
+ lastDeferCount int // Number of defers encountered at that point
+
+ prevCall *ssa.Value // the previous call; use this to tie results to the call op.
+}
+
+type funcLine struct {
+ f *obj.LSym
+ base *src.PosBase
+ line uint
+}
+
+type ssaLabel struct {
+ target *ssa.Block // block identified by this label
+ breakTarget *ssa.Block // block to break to in control flow node identified by this label
+ continueTarget *ssa.Block // block to continue to in control flow node identified by this label
+}
+
+// label returns the label associated with sym, creating it if necessary.
+func (s *state) label(sym *types.Sym) *ssaLabel {
+ lab := s.labels[sym.Name]
+ if lab == nil {
+ lab = new(ssaLabel)
+ s.labels[sym.Name] = lab
+ }
+ return lab
+}
+
+func (s *state) Logf(msg string, args ...interface{}) { s.f.Logf(msg, args...) }
+func (s *state) Log() bool { return s.f.Log() }
+func (s *state) Fatalf(msg string, args ...interface{}) {
+ s.f.Frontend().Fatalf(s.peekPos(), msg, args...)
+}
+func (s *state) Warnl(pos src.XPos, msg string, args ...interface{}) { s.f.Warnl(pos, msg, args...) }
+func (s *state) Debug_checknil() bool { return s.f.Frontend().Debug_checknil() }
+
+var (
+ // dummy node for the memory variable
+ memVar = Node{Op: ONAME, Sym: &types.Sym{Name: "mem"}}
+
+ // dummy nodes for temporary variables
+ ptrVar = Node{Op: ONAME, Sym: &types.Sym{Name: "ptr"}}
+ lenVar = Node{Op: ONAME, Sym: &types.Sym{Name: "len"}}
+ newlenVar = Node{Op: ONAME, Sym: &types.Sym{Name: "newlen"}}
+ capVar = Node{Op: ONAME, Sym: &types.Sym{Name: "cap"}}
+ typVar = Node{Op: ONAME, Sym: &types.Sym{Name: "typ"}}
+ okVar = Node{Op: ONAME, Sym: &types.Sym{Name: "ok"}}
+ deferBitsVar = Node{Op: ONAME, Sym: &types.Sym{Name: "deferBits"}}
+)
+
+// startBlock sets the current block we're generating code in to b.
+func (s *state) startBlock(b *ssa.Block) {
+ if s.curBlock != nil {
+ s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
+ }
+ s.curBlock = b
+ s.vars = map[*Node]*ssa.Value{}
+ for n := range s.fwdVars {
+ delete(s.fwdVars, n)
+ }
+}
+
+// endBlock marks the end of generating code for the current block.
+// Returns the (former) current block. Returns nil if there is no current
+// block, i.e. if no code flows to the current execution point.
+func (s *state) endBlock() *ssa.Block {
+ b := s.curBlock
+ if b == nil {
+ return nil
+ }
+ for len(s.defvars) <= int(b.ID) {
+ s.defvars = append(s.defvars, nil)
+ }
+ s.defvars[b.ID] = s.vars
+ s.curBlock = nil
+ s.vars = nil
+ if b.LackingPos() {
+ // Empty plain blocks get the line of their successor (handled after all blocks created),
+ // except for increment blocks in For statements (handled in ssa conversion of OFOR),
+ // and for blocks ending in GOTO/BREAK/CONTINUE.
+ b.Pos = src.NoXPos
+ } else {
+ b.Pos = s.lastPos
+ }
+ return b
+}
+
+// pushLine pushes a line number on the line number stack.
+func (s *state) pushLine(line src.XPos) {
+ if !line.IsKnown() {
+ // the frontend may emit node with line number missing,
+ // use the parent line number in this case.
+ line = s.peekPos()
+ if Debug.K != 0 {
+ Warn("buildssa: unknown position (line 0)")
+ }
+ } else {
+ s.lastPos = line
+ }
+
+ s.line = append(s.line, line)
+}
+
+// popLine pops the top of the line number stack.
+func (s *state) popLine() {
+ s.line = s.line[:len(s.line)-1]
+}
+
+// peekPos peeks the top of the line number stack.
+func (s *state) peekPos() src.XPos {
+ return s.line[len(s.line)-1]
+}
+
+// newValue0 adds a new value with no arguments to the current block.
+func (s *state) newValue0(op ssa.Op, t *types.Type) *ssa.Value {
+ return s.curBlock.NewValue0(s.peekPos(), op, t)
+}
+
+// newValue0A adds a new value with no arguments and an aux value to the current block.
+func (s *state) newValue0A(op ssa.Op, t *types.Type, aux interface{}) *ssa.Value {
+ return s.curBlock.NewValue0A(s.peekPos(), op, t, aux)
+}
+
+// newValue0I adds a new value with no arguments and an auxint value to the current block.
+func (s *state) newValue0I(op ssa.Op, t *types.Type, auxint int64) *ssa.Value {
+ return s.curBlock.NewValue0I(s.peekPos(), op, t, auxint)
+}
+
+// newValue1 adds a new value with one argument to the current block.
+func (s *state) newValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue1(s.peekPos(), op, t, arg)
+}
+
+// newValue1A adds a new value with one argument and an aux value to the current block.
+func (s *state) newValue1A(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg)
+}
+
+// newValue1Apos adds a new value with one argument and an aux value to the current block.
+// isStmt determines whether the created values may be a statement or not
+// (i.e., false means never, yes means maybe).
+func (s *state) newValue1Apos(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value, isStmt bool) *ssa.Value {
+ if isStmt {
+ return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg)
+ }
+ return s.curBlock.NewValue1A(s.peekPos().WithNotStmt(), op, t, aux, arg)
+}
+
+// newValue1I adds a new value with one argument and an auxint value to the current block.
+func (s *state) newValue1I(op ssa.Op, t *types.Type, aux int64, arg *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue1I(s.peekPos(), op, t, aux, arg)
+}
+
+// newValue2 adds a new value with two arguments to the current block.
+func (s *state) newValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue2(s.peekPos(), op, t, arg0, arg1)
+}
+
+// newValue2A adds a new value with two arguments and an aux value to the current block.
+func (s *state) newValue2A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue2A(s.peekPos(), op, t, aux, arg0, arg1)
+}
+
+// newValue2Apos adds a new value with two arguments and an aux value to the current block.
+// isStmt determines whether the created values may be a statement or not
+// (i.e., false means never, yes means maybe).
+func (s *state) newValue2Apos(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value, isStmt bool) *ssa.Value {
+ if isStmt {
+ return s.curBlock.NewValue2A(s.peekPos(), op, t, aux, arg0, arg1)
+ }
+ return s.curBlock.NewValue2A(s.peekPos().WithNotStmt(), op, t, aux, arg0, arg1)
+}
+
+// newValue2I adds a new value with two arguments and an auxint value to the current block.
+func (s *state) newValue2I(op ssa.Op, t *types.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue2I(s.peekPos(), op, t, aux, arg0, arg1)
+}
+
+// newValue3 adds a new value with three arguments to the current block.
+func (s *state) newValue3(op ssa.Op, t *types.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue3(s.peekPos(), op, t, arg0, arg1, arg2)
+}
+
+// newValue3I adds a new value with three arguments and an auxint value to the current block.
+func (s *state) newValue3I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue3I(s.peekPos(), op, t, aux, arg0, arg1, arg2)
+}
+
+// newValue3A adds a new value with three arguments and an aux value to the current block.
+func (s *state) newValue3A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue3A(s.peekPos(), op, t, aux, arg0, arg1, arg2)
+}
+
+// newValue3Apos adds a new value with three arguments and an aux value to the current block.
+// isStmt determines whether the created values may be a statement or not
+// (i.e., false means never, yes means maybe).
+func (s *state) newValue3Apos(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *ssa.Value, isStmt bool) *ssa.Value {
+ if isStmt {
+ return s.curBlock.NewValue3A(s.peekPos(), op, t, aux, arg0, arg1, arg2)
+ }
+ return s.curBlock.NewValue3A(s.peekPos().WithNotStmt(), 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 *types.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue4(s.peekPos(), op, t, arg0, arg1, arg2, arg3)
+}
+
+// newValue4 adds a new value with four arguments and an auxint value to the current block.
+func (s *state) newValue4I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue4I(s.peekPos(), op, t, aux, arg0, arg1, arg2, arg3)
+}
+
+// entryNewValue0 adds a new value with no arguments to the entry block.
+func (s *state) entryNewValue0(op ssa.Op, t *types.Type) *ssa.Value {
+ return s.f.Entry.NewValue0(src.NoXPos, op, t)
+}
+
+// entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
+func (s *state) entryNewValue0A(op ssa.Op, t *types.Type, aux interface{}) *ssa.Value {
+ return s.f.Entry.NewValue0A(src.NoXPos, op, t, aux)
+}
+
+// entryNewValue1 adds a new value with one argument to the entry block.
+func (s *state) entryNewValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value {
+ return s.f.Entry.NewValue1(src.NoXPos, op, t, arg)
+}
+
+// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
+func (s *state) entryNewValue1I(op ssa.Op, t *types.Type, auxint int64, arg *ssa.Value) *ssa.Value {
+ return s.f.Entry.NewValue1I(src.NoXPos, op, t, auxint, arg)
+}
+
+// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
+func (s *state) entryNewValue1A(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
+ return s.f.Entry.NewValue1A(src.NoXPos, op, t, aux, arg)
+}
+
+// entryNewValue2 adds a new value with two arguments to the entry block.
+func (s *state) entryNewValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value {
+ return s.f.Entry.NewValue2(src.NoXPos, op, t, arg0, arg1)
+}
+
+// entryNewValue2A adds a new value with two arguments and an aux value to the entry block.
+func (s *state) entryNewValue2A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value {
+ return s.f.Entry.NewValue2A(src.NoXPos, op, t, aux, arg0, arg1)
+}
+
+// const* routines add a new const value to the entry block.
+func (s *state) constSlice(t *types.Type) *ssa.Value {
+ return s.f.ConstSlice(t)
+}
+func (s *state) constInterface(t *types.Type) *ssa.Value {
+ return s.f.ConstInterface(t)
+}
+func (s *state) constNil(t *types.Type) *ssa.Value { return s.f.ConstNil(t) }
+func (s *state) constEmptyString(t *types.Type) *ssa.Value {
+ return s.f.ConstEmptyString(t)
+}
+func (s *state) constBool(c bool) *ssa.Value {
+ return s.f.ConstBool(types.Types[TBOOL], c)
+}
+func (s *state) constInt8(t *types.Type, c int8) *ssa.Value {
+ return s.f.ConstInt8(t, c)
+}
+func (s *state) constInt16(t *types.Type, c int16) *ssa.Value {
+ return s.f.ConstInt16(t, c)
+}
+func (s *state) constInt32(t *types.Type, c int32) *ssa.Value {
+ return s.f.ConstInt32(t, c)
+}
+func (s *state) constInt64(t *types.Type, c int64) *ssa.Value {
+ return s.f.ConstInt64(t, c)
+}
+func (s *state) constFloat32(t *types.Type, c float64) *ssa.Value {
+ return s.f.ConstFloat32(t, c)
+}
+func (s *state) constFloat64(t *types.Type, c float64) *ssa.Value {
+ return s.f.ConstFloat64(t, c)
+}
+func (s *state) constInt(t *types.Type, c int64) *ssa.Value {
+ if s.config.PtrSize == 8 {
+ return s.constInt64(t, c)
+ }
+ if int64(int32(c)) != c {
+ s.Fatalf("integer constant too big %d", c)
+ }
+ return s.constInt32(t, int32(c))
+}
+func (s *state) constOffPtrSP(t *types.Type, c int64) *ssa.Value {
+ return s.f.ConstOffPtrSP(t, c, s.sp)
+}
+
+// newValueOrSfCall* are wrappers around newValue*, which may create a call to a
+// soft-float runtime function instead (when emitting soft-float code).
+func (s *state) newValueOrSfCall1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value {
+ if s.softFloat {
+ if c, ok := s.sfcall(op, arg); ok {
+ return c
+ }
+ }
+ return s.newValue1(op, t, arg)
+}
+func (s *state) newValueOrSfCall2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value {
+ if s.softFloat {
+ if c, ok := s.sfcall(op, arg0, arg1); ok {
+ return c
+ }
+ }
+ return s.newValue2(op, t, arg0, arg1)
+}
+
+type instrumentKind uint8
+
+const (
+ instrumentRead = iota
+ instrumentWrite
+ instrumentMove
+)
+
+func (s *state) instrument(t *types.Type, addr *ssa.Value, kind instrumentKind) {
+ s.instrument2(t, addr, nil, kind)
+}
+
+// instrumentFields instruments a read/write operation on addr.
+// If it is instrumenting for MSAN and t is a struct type, it instruments
+// operation for each field, instead of for the whole struct.
+func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrumentKind) {
+ if !flag_msan || !t.IsStruct() {
+ s.instrument(t, addr, kind)
+ return
+ }
+ for _, f := range t.Fields().Slice() {
+ if f.Sym.IsBlank() {
+ continue
+ }
+ offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr)
+ s.instrumentFields(f.Type, offptr, kind)
+ }
+}
+
+func (s *state) instrumentMove(t *types.Type, dst, src *ssa.Value) {
+ if flag_msan {
+ s.instrument2(t, dst, src, instrumentMove)
+ } else {
+ s.instrument(t, src, instrumentRead)
+ s.instrument(t, dst, instrumentWrite)
+ }
+}
+
+func (s *state) instrument2(t *types.Type, addr, addr2 *ssa.Value, kind instrumentKind) {
+ if !s.curfn.Func.InstrumentBody() {
+ return
+ }
+
+ w := t.Size()
+ if w == 0 {
+ return // can't race on zero-sized things
+ }
+
+ if ssa.IsSanitizerSafeAddr(addr) {
+ return
+ }
+
+ var fn *obj.LSym
+ needWidth := false
+
+ if addr2 != nil && kind != instrumentMove {
+ panic("instrument2: non-nil addr2 for non-move instrumentation")
+ }
+
+ if flag_msan {
+ switch kind {
+ case instrumentRead:
+ fn = msanread
+ case instrumentWrite:
+ fn = msanwrite
+ case instrumentMove:
+ fn = msanmove
+ default:
+ panic("unreachable")
+ }
+ needWidth = true
+ } else if flag_race && t.NumComponents(types.CountBlankFields) > 1 {
+ // for composite objects we have to write every address
+ // because a write might happen to any subobject.
+ // composites with only one element don't have subobjects, though.
+ switch kind {
+ case instrumentRead:
+ fn = racereadrange
+ case instrumentWrite:
+ fn = racewriterange
+ default:
+ panic("unreachable")
+ }
+ needWidth = true
+ } else if flag_race {
+ // for non-composite objects we can write just the start
+ // address, as any write must write the first byte.
+ switch kind {
+ case instrumentRead:
+ fn = raceread
+ case instrumentWrite:
+ fn = racewrite
+ default:
+ panic("unreachable")
+ }
+ } else {
+ panic("unreachable")
+ }
+
+ args := []*ssa.Value{addr}
+ if addr2 != nil {
+ args = append(args, addr2)
+ }
+ if needWidth {
+ args = append(args, s.constInt(types.Types[TUINTPTR], w))
+ }
+ s.rtcall(fn, true, nil, args...)
+}
+
+func (s *state) load(t *types.Type, src *ssa.Value) *ssa.Value {
+ s.instrumentFields(t, src, instrumentRead)
+ return s.rawLoad(t, src)
+}
+
+func (s *state) rawLoad(t *types.Type, src *ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpLoad, t, src, s.mem())
+}
+
+func (s *state) store(t *types.Type, dst, val *ssa.Value) {
+ s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, dst, val, s.mem())
+}
+
+func (s *state) zero(t *types.Type, dst *ssa.Value) {
+ s.instrument(t, dst, instrumentWrite)
+ store := s.newValue2I(ssa.OpZero, types.TypeMem, t.Size(), dst, s.mem())
+ store.Aux = t
+ s.vars[&memVar] = store
+}
+
+func (s *state) move(t *types.Type, dst, src *ssa.Value) {
+ s.instrumentMove(t, dst, src)
+ store := s.newValue3I(ssa.OpMove, types.TypeMem, t.Size(), dst, src, s.mem())
+ store.Aux = t
+ s.vars[&memVar] = store
+}
+
+// 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)
+ }
+}
+
+// stmt converts the statement n to SSA and adds it to s.
+func (s *state) stmt(n *Node) {
+ if !(n.Op == OVARKILL || n.Op == OVARLIVE || n.Op == OVARDEF) {
+ // OVARKILL, OVARLIVE, and OVARDEF are invisible to the programmer, so we don't use their line numbers to avoid confusion in debugging.
+ s.pushLine(n.Pos)
+ defer s.popLine()
+ }
+
+ // If s.curBlock is nil, and n isn't a label (which might have an associated goto somewhere),
+ // then this code is dead. Stop here.
+ if s.curBlock == nil && n.Op != OLABEL {
+ return
+ }
+
+ s.stmtList(n.Ninit)
+ switch n.Op {
+
+ case OBLOCK:
+ s.stmtList(n.List)
+
+ // No-ops
+ case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
+
+ // Expression statements
+ case OCALLFUNC:
+ if isIntrinsicCall(n) {
+ s.intrinsicCall(n)
+ return
+ }
+ fallthrough
+
+ case OCALLMETH, OCALLINTER:
+ s.callResult(n, callNormal)
+ 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 == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap") {
+ 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:
+ if Debug_defer > 0 {
+ var defertype string
+ if s.hasOpenDefers {
+ defertype = "open-coded"
+ } else if n.Esc == EscNever {
+ defertype = "stack-allocated"
+ } else {
+ defertype = "heap-allocated"
+ }
+ Warnl(n.Pos, "%s defer", defertype)
+ }
+ if s.hasOpenDefers {
+ s.openDeferRecord(n.Left)
+ } else {
+ d := callDefer
+ if n.Esc == EscNever {
+ d = callDeferStack
+ }
+ s.callResult(n.Left, d)
+ }
+ case OGO:
+ s.callResult(n.Left, callGo)
+
+ case OAS2DOTTYPE:
+ res, resok := s.dottype(n.Right, true)
+ deref := false
+ if !canSSAType(n.Right.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, deref, 0)
+ s.assign(n.List.Second(), resok, false, 0)
+ return
+
+ case OAS2FUNC:
+ // We come here only when it is an intrinsic call returning two values.
+ if !isIntrinsicCall(n.Right) {
+ s.Fatalf("non-intrinsic AS2FUNC not expanded %v", n.Right)
+ }
+ v := s.intrinsicCall(n.Right)
+ v1 := s.newValue1(ssa.OpSelect0, n.List.First().Type, v)
+ v2 := s.newValue1(ssa.OpSelect1, n.List.Second().Type, v)
+ s.assign(n.List.First(), v1, false, 0)
+ s.assign(n.List.Second(), v2, false, 0)
+ return
+
+ case ODCL:
+ if n.Left.Class() == PAUTOHEAP {
+ s.Fatalf("DCL %v", n)
+ }
+
+ case OLABEL:
+ sym := n.Sym
+ lab := s.label(sym)
+
+ // Associate label with its control flow node, if any
+ if ctl := n.labeledControl(); ctl != nil {
+ s.labeledNodes[ctl] = lab
+ }
+
+ // The label might already have a target block via a goto.
+ if lab.target == nil {
+ lab.target = s.f.NewBlock(ssa.BlockPlain)
+ }
+
+ // Go to that label.
+ // (We pretend "label:" is preceded by "goto label", unless the predecessor is unreachable.)
+ if s.curBlock != nil {
+ b := s.endBlock()
+ b.AddEdgeTo(lab.target)
+ }
+ s.startBlock(lab.target)
+
+ case OGOTO:
+ sym := n.Sym
+
+ lab := s.label(sym)
+ if lab.target == nil {
+ lab.target = s.f.NewBlock(ssa.BlockPlain)
+ }
+
+ b := s.endBlock()
+ b.Pos = s.lastPos.WithIsStmt() // Do this even if b is an empty block.
+ b.AddEdgeTo(lab.target)
+
+ case OAS:
+ if n.Left == n.Right && n.Left.Op == ONAME {
+ // An x=x assignment. No point in doing anything
+ // here. In addition, skipping this assignment
+ // prevents generating:
+ // VARDEF x
+ // COPY x -> x
+ // which is bad because x is incorrectly considered
+ // dead before the vardef. See issue #14904.
+ return
+ }
+
+ // Evaluate RHS.
+ rhs := n.Right
+ if rhs != nil {
+ switch rhs.Op {
+ 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.
+ if !isZero(rhs) {
+ s.Fatalf("literal with nonzero value in SSA: %v", rhs)
+ }
+ rhs = nil
+ case OAPPEND:
+ // Check whether we're writing the result of an append back to the same slice.
+ // If so, we handle it specially to avoid write barriers on the fast
+ // (non-growth) path.
+ if !samesafeexpr(n.Left, rhs.List.First()) || Debug.N != 0 {
+ break
+ }
+ // 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 s.canSSA(n.Left) {
+ if Debug_append > 0 { // replicating old diagnostic message
+ Warnl(n.Pos, "append: len-only update (in local slice)")
+ }
+ break
+ }
+ if Debug_append > 0 {
+ Warnl(n.Pos, "append: len-only update")
+ }
+ s.append(rhs, true)
+ return
+ }
+ }
+
+ if n.Left.isBlank() {
+ // _ = rhs
+ // Just evaluate rhs for side-effects.
+ if rhs != nil {
+ s.expr(rhs)
+ }
+ return
+ }
+
+ var t *types.Type
+ if n.Right != nil {
+ t = n.Right.Type
+ } else {
+ t = n.Left.Type
+ }
+
+ var r *ssa.Value
+ deref := !canSSAType(t)
+ if deref {
+ if rhs == nil {
+ r = nil // Signal assign to use OpZero.
+ } else {
+ r = s.addr(rhs)
+ }
+ } else {
+ if rhs == nil {
+ r = s.zeroVal(t)
+ } else {
+ r = s.expr(rhs)
+ }
+ }
+
+ var skip skipMask
+ if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) {
+ // We're assigning a slicing operation back to its source.
+ // Don't write back fields we aren't changing. See issue #14855.
+ i, j, k := rhs.SliceBounds()
+ if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64Val() == 0) {
+ // [0:...] is the same as [:...]
+ i = nil
+ }
+ // TODO: detect defaults for len/cap also.
+ // Currently doesn't really work because (*p)[:len(*p)] appears here as:
+ // tmp = len(*p)
+ // (*p)[:tmp]
+ //if j != nil && (j.Op == OLEN && samesafeexpr(j.Left, n.Left)) {
+ // j = nil
+ //}
+ //if k != nil && (k.Op == OCAP && samesafeexpr(k.Left, n.Left)) {
+ // k = nil
+ //}
+ if i == nil {
+ skip |= skipPtr
+ if j == nil {
+ skip |= skipLen
+ }
+ if k == nil {
+ skip |= skipCap
+ }
+ }
+ }
+
+ s.assign(n.Left, r, deref, skip)
+
+ case OIF:
+ if Isconst(n.Left, CTBOOL) {
+ s.stmtList(n.Left.Ninit)
+ if n.Left.BoolVal() {
+ s.stmtList(n.Nbody)
+ } else {
+ s.stmtList(n.Rlist)
+ }
+ break
+ }
+
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+ var likely int8
+ if n.Likely() {
+ likely = 1
+ }
+ var bThen *ssa.Block
+ if n.Nbody.Len() != 0 {
+ bThen = s.f.NewBlock(ssa.BlockPlain)
+ } else {
+ bThen = bEnd
+ }
+ var bElse *ssa.Block
+ if n.Rlist.Len() != 0 {
+ bElse = s.f.NewBlock(ssa.BlockPlain)
+ } else {
+ bElse = bEnd
+ }
+ s.condBranch(n.Left, bThen, bElse, likely)
+
+ if n.Nbody.Len() != 0 {
+ s.startBlock(bThen)
+ s.stmtList(n.Nbody)
+ if b := s.endBlock(); b != nil {
+ b.AddEdgeTo(bEnd)
+ }
+ }
+ if n.Rlist.Len() != 0 {
+ s.startBlock(bElse)
+ s.stmtList(n.Rlist)
+ if b := s.endBlock(); b != nil {
+ b.AddEdgeTo(bEnd)
+ }
+ }
+ s.startBlock(bEnd)
+
+ case ORETURN:
+ s.stmtList(n.List)
+ b := s.exit()
+ b.Pos = s.lastPos.WithIsStmt()
+
+ case ORETJMP:
+ s.stmtList(n.List)
+ b := s.exit()
+ b.Kind = ssa.BlockRetJmp // override BlockRet
+ b.Aux = n.Sym.Linksym()
+
+ case OCONTINUE, OBREAK:
+ var to *ssa.Block
+ if n.Sym == nil {
+ // plain break/continue
+ switch n.Op {
+ case OCONTINUE:
+ to = s.continueTo
+ case OBREAK:
+ to = s.breakTo
+ }
+ } else {
+ // labeled break/continue; look up the target
+ sym := n.Sym
+ lab := s.label(sym)
+ switch n.Op {
+ case OCONTINUE:
+ to = lab.continueTarget
+ case OBREAK:
+ to = lab.breakTarget
+ }
+ }
+
+ b := s.endBlock()
+ b.Pos = s.lastPos.WithIsStmt() // Do this even if b is an empty block.
+ b.AddEdgeTo(to)
+
+ case OFOR, OFORUNTIL:
+ // OFOR: for Ninit; Left; Right { Nbody }
+ // cond (Left); body (Nbody); incr (Right)
+ //
+ // OFORUNTIL: for Ninit; Left; Right; List { Nbody }
+ // => body: { Nbody }; incr: Right; if Left { lateincr: List; goto body }; end:
+ bCond := s.f.NewBlock(ssa.BlockPlain)
+ bBody := s.f.NewBlock(ssa.BlockPlain)
+ bIncr := s.f.NewBlock(ssa.BlockPlain)
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+ // ensure empty for loops have correct position; issue #30167
+ bBody.Pos = n.Pos
+
+ // first, jump to condition test (OFOR) or body (OFORUNTIL)
+ b := s.endBlock()
+ if n.Op == OFOR {
+ b.AddEdgeTo(bCond)
+ // generate code to test condition
+ s.startBlock(bCond)
+ if n.Left != nil {
+ s.condBranch(n.Left, bBody, bEnd, 1)
+ } else {
+ b := s.endBlock()
+ b.Kind = ssa.BlockPlain
+ b.AddEdgeTo(bBody)
+ }
+
+ } else {
+ b.AddEdgeTo(bBody)
+ }
+
+ // set up for continue/break in body
+ prevContinue := s.continueTo
+ prevBreak := s.breakTo
+ s.continueTo = bIncr
+ s.breakTo = bEnd
+ lab := s.labeledNodes[n]
+ if lab != nil {
+ // labeled for loop
+ lab.continueTarget = bIncr
+ lab.breakTarget = bEnd
+ }
+
+ // generate body
+ s.startBlock(bBody)
+ s.stmtList(n.Nbody)
+
+ // tear down continue/break
+ s.continueTo = prevContinue
+ s.breakTo = prevBreak
+ if lab != nil {
+ lab.continueTarget = nil
+ lab.breakTarget = nil
+ }
+
+ // done with body, goto incr
+ if b := s.endBlock(); b != nil {
+ b.AddEdgeTo(bIncr)
+ }
+
+ // generate incr (and, for OFORUNTIL, condition)
+ s.startBlock(bIncr)
+ if n.Right != nil {
+ s.stmt(n.Right)
+ }
+ if n.Op == OFOR {
+ if b := s.endBlock(); b != nil {
+ b.AddEdgeTo(bCond)
+ // It can happen that bIncr ends in a block containing only VARKILL,
+ // and that muddles the debugging experience.
+ if n.Op != OFORUNTIL && b.Pos == src.NoXPos {
+ b.Pos = bCond.Pos
+ }
+ }
+ } else {
+ // bCond is unused in OFORUNTIL, so repurpose it.
+ bLateIncr := bCond
+ // test condition
+ s.condBranch(n.Left, bLateIncr, bEnd, 1)
+ // generate late increment
+ s.startBlock(bLateIncr)
+ s.stmtList(n.List)
+ s.endBlock().AddEdgeTo(bBody)
+ }
+
+ s.startBlock(bEnd)
+
+ case OSWITCH, OSELECT:
+ // These have been mostly rewritten by the front end into their Nbody fields.
+ // Our main task is to correctly hook up any break statements.
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+ prevBreak := s.breakTo
+ s.breakTo = bEnd
+ lab := s.labeledNodes[n]
+ if lab != nil {
+ // labeled
+ lab.breakTarget = bEnd
+ }
+
+ // generate body code
+ s.stmtList(n.Nbody)
+
+ s.breakTo = prevBreak
+ if lab != nil {
+ lab.breakTarget = nil
+ }
+
+ // walk adds explicit OBREAK nodes to the end of all reachable code paths.
+ // If we still have a current block here, then mark it unreachable.
+ if s.curBlock != nil {
+ m := s.mem()
+ b := s.endBlock()
+ b.Kind = ssa.BlockExit
+ b.SetControl(m)
+ }
+ s.startBlock(bEnd)
+
+ case OVARDEF:
+ if !s.canSSA(n.Left) {
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, n.Left, s.mem(), false)
+ }
+ case OVARKILL:
+ // Insert a varkill op to record that a variable is no longer live.
+ // We only care about liveness info at call sites, so putting the
+ // varkill in the store chain is enough to keep it correctly ordered
+ // with respect to call ops.
+ if !s.canSSA(n.Left) {
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarKill, types.TypeMem, n.Left, s.mem(), false)
+ }
+
+ case OVARLIVE:
+ // Insert a varlive op to record that a variable is still live.
+ if !n.Left.Name.Addrtaken() {
+ s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left)
+ }
+ switch n.Left.Class() {
+ case PAUTO, PPARAM, PPARAMOUT:
+ default:
+ s.Fatalf("VARLIVE variable %v must be Auto or Arg", n.Left)
+ }
+ s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, n.Left, s.mem())
+
+ case OCHECKNIL:
+ p := s.expr(n.Left)
+ s.nilCheck(p)
+
+ case OINLMARK:
+ s.newValue1I(ssa.OpInlMark, types.TypeVoid, n.Xoffset, s.mem())
+
+ default:
+ s.Fatalf("unhandled stmt %v", n.Op)
+ }
+}
+
+// If true, share as many open-coded defer exits as possible (with the downside of
+// worse line-number information)
+const shareDeferExits = false
+
+// exit processes any code that needs to be generated just before returning.
+// It returns a BlockRet block that ends the control flow. Its control value
+// will be set to the final memory state.
+func (s *state) exit() *ssa.Block {
+ if s.hasdefer {
+ if s.hasOpenDefers {
+ if shareDeferExits && s.lastDeferExit != nil && len(s.openDefers) == s.lastDeferCount {
+ if s.curBlock.Kind != ssa.BlockPlain {
+ panic("Block for an exit should be BlockPlain")
+ }
+ s.curBlock.AddEdgeTo(s.lastDeferExit)
+ s.endBlock()
+ return s.lastDeferFinalBlock
+ }
+ s.openDeferExit()
+ } else {
+ s.rtcall(Deferreturn, true, nil)
+ }
+ }
+
+ // Run exit code. Typically, this code copies heap-allocated PPARAMOUT
+ // variables back to the stack.
+ s.stmtList(s.curfn.Func.Exit)
+
+ // Store SSAable PPARAMOUT variables back to stack locations.
+ for _, n := range s.returns {
+ addr := s.decladdrs[n]
+ val := s.variable(n, n.Type)
+ s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem())
+ s.store(n.Type, addr, val)
+ // TODO: if val is ever spilled, we'd like to use the
+ // PPARAMOUT slot for spilling it. That won't happen
+ // currently.
+ }
+
+ // Do actual return.
+ m := s.mem()
+ b := s.endBlock()
+ b.Kind = ssa.BlockRet
+ b.SetControl(m)
+ if s.hasdefer && s.hasOpenDefers {
+ s.lastDeferFinalBlock = b
+ }
+ return b
+}
+
+type opAndType struct {
+ op Op
+ etype types.EType
+}
+
+var opToSSA = map[opAndType]ssa.Op{
+ opAndType{OADD, TINT8}: ssa.OpAdd8,
+ opAndType{OADD, TUINT8}: ssa.OpAdd8,
+ opAndType{OADD, TINT16}: ssa.OpAdd16,
+ opAndType{OADD, TUINT16}: ssa.OpAdd16,
+ opAndType{OADD, TINT32}: ssa.OpAdd32,
+ opAndType{OADD, TUINT32}: ssa.OpAdd32,
+ opAndType{OADD, TINT64}: ssa.OpAdd64,
+ opAndType{OADD, TUINT64}: ssa.OpAdd64,
+ opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
+ opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
+
+ opAndType{OSUB, TINT8}: ssa.OpSub8,
+ opAndType{OSUB, TUINT8}: ssa.OpSub8,
+ opAndType{OSUB, TINT16}: ssa.OpSub16,
+ opAndType{OSUB, TUINT16}: ssa.OpSub16,
+ opAndType{OSUB, TINT32}: ssa.OpSub32,
+ opAndType{OSUB, TUINT32}: ssa.OpSub32,
+ opAndType{OSUB, TINT64}: ssa.OpSub64,
+ opAndType{OSUB, TUINT64}: ssa.OpSub64,
+ opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
+ opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
+
+ opAndType{ONOT, TBOOL}: ssa.OpNot,
+
+ opAndType{ONEG, TINT8}: ssa.OpNeg8,
+ opAndType{ONEG, TUINT8}: ssa.OpNeg8,
+ opAndType{ONEG, TINT16}: ssa.OpNeg16,
+ opAndType{ONEG, TUINT16}: ssa.OpNeg16,
+ opAndType{ONEG, TINT32}: ssa.OpNeg32,
+ opAndType{ONEG, TUINT32}: ssa.OpNeg32,
+ opAndType{ONEG, TINT64}: ssa.OpNeg64,
+ opAndType{ONEG, TUINT64}: ssa.OpNeg64,
+ opAndType{ONEG, TFLOAT32}: ssa.OpNeg32F,
+ opAndType{ONEG, TFLOAT64}: ssa.OpNeg64F,
+
+ opAndType{OBITNOT, TINT8}: ssa.OpCom8,
+ opAndType{OBITNOT, TUINT8}: ssa.OpCom8,
+ opAndType{OBITNOT, TINT16}: ssa.OpCom16,
+ opAndType{OBITNOT, TUINT16}: ssa.OpCom16,
+ opAndType{OBITNOT, TINT32}: ssa.OpCom32,
+ opAndType{OBITNOT, TUINT32}: ssa.OpCom32,
+ opAndType{OBITNOT, TINT64}: ssa.OpCom64,
+ opAndType{OBITNOT, TUINT64}: ssa.OpCom64,
+
+ opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
+ opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
+ opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
+ opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
+
+ opAndType{OMUL, TINT8}: ssa.OpMul8,
+ opAndType{OMUL, TUINT8}: ssa.OpMul8,
+ opAndType{OMUL, TINT16}: ssa.OpMul16,
+ opAndType{OMUL, TUINT16}: ssa.OpMul16,
+ opAndType{OMUL, TINT32}: ssa.OpMul32,
+ opAndType{OMUL, TUINT32}: ssa.OpMul32,
+ opAndType{OMUL, TINT64}: ssa.OpMul64,
+ opAndType{OMUL, TUINT64}: ssa.OpMul64,
+ opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
+ opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
+
+ opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
+ opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
+
+ opAndType{ODIV, TINT8}: ssa.OpDiv8,
+ opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
+ opAndType{ODIV, TINT16}: ssa.OpDiv16,
+ opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
+ opAndType{ODIV, TINT32}: ssa.OpDiv32,
+ opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
+ opAndType{ODIV, TINT64}: ssa.OpDiv64,
+ opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
+
+ opAndType{OMOD, TINT8}: ssa.OpMod8,
+ opAndType{OMOD, TUINT8}: ssa.OpMod8u,
+ opAndType{OMOD, TINT16}: ssa.OpMod16,
+ opAndType{OMOD, TUINT16}: ssa.OpMod16u,
+ opAndType{OMOD, TINT32}: ssa.OpMod32,
+ opAndType{OMOD, TUINT32}: ssa.OpMod32u,
+ opAndType{OMOD, TINT64}: ssa.OpMod64,
+ opAndType{OMOD, TUINT64}: ssa.OpMod64u,
+
+ opAndType{OAND, TINT8}: ssa.OpAnd8,
+ opAndType{OAND, TUINT8}: ssa.OpAnd8,
+ opAndType{OAND, TINT16}: ssa.OpAnd16,
+ opAndType{OAND, TUINT16}: ssa.OpAnd16,
+ opAndType{OAND, TINT32}: ssa.OpAnd32,
+ opAndType{OAND, TUINT32}: ssa.OpAnd32,
+ opAndType{OAND, TINT64}: ssa.OpAnd64,
+ opAndType{OAND, TUINT64}: ssa.OpAnd64,
+
+ opAndType{OOR, TINT8}: ssa.OpOr8,
+ opAndType{OOR, TUINT8}: ssa.OpOr8,
+ opAndType{OOR, TINT16}: ssa.OpOr16,
+ opAndType{OOR, TUINT16}: ssa.OpOr16,
+ opAndType{OOR, TINT32}: ssa.OpOr32,
+ opAndType{OOR, TUINT32}: ssa.OpOr32,
+ opAndType{OOR, TINT64}: ssa.OpOr64,
+ opAndType{OOR, TUINT64}: ssa.OpOr64,
+
+ opAndType{OXOR, TINT8}: ssa.OpXor8,
+ opAndType{OXOR, TUINT8}: ssa.OpXor8,
+ opAndType{OXOR, TINT16}: ssa.OpXor16,
+ opAndType{OXOR, TUINT16}: ssa.OpXor16,
+ opAndType{OXOR, TINT32}: ssa.OpXor32,
+ opAndType{OXOR, TUINT32}: ssa.OpXor32,
+ opAndType{OXOR, TINT64}: ssa.OpXor64,
+ opAndType{OXOR, TUINT64}: ssa.OpXor64,
+
+ opAndType{OEQ, TBOOL}: ssa.OpEqB,
+ opAndType{OEQ, TINT8}: ssa.OpEq8,
+ opAndType{OEQ, TUINT8}: ssa.OpEq8,
+ opAndType{OEQ, TINT16}: ssa.OpEq16,
+ opAndType{OEQ, TUINT16}: ssa.OpEq16,
+ opAndType{OEQ, TINT32}: ssa.OpEq32,
+ opAndType{OEQ, TUINT32}: ssa.OpEq32,
+ opAndType{OEQ, TINT64}: ssa.OpEq64,
+ opAndType{OEQ, TUINT64}: ssa.OpEq64,
+ opAndType{OEQ, TINTER}: ssa.OpEqInter,
+ opAndType{OEQ, TSLICE}: ssa.OpEqSlice,
+ opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
+ opAndType{OEQ, TMAP}: ssa.OpEqPtr,
+ opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
+ opAndType{OEQ, TPTR}: ssa.OpEqPtr,
+ opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
+ opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
+ opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
+ opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
+
+ opAndType{ONE, TBOOL}: ssa.OpNeqB,
+ opAndType{ONE, TINT8}: ssa.OpNeq8,
+ opAndType{ONE, TUINT8}: ssa.OpNeq8,
+ opAndType{ONE, TINT16}: ssa.OpNeq16,
+ opAndType{ONE, TUINT16}: ssa.OpNeq16,
+ opAndType{ONE, TINT32}: ssa.OpNeq32,
+ opAndType{ONE, TUINT32}: ssa.OpNeq32,
+ opAndType{ONE, TINT64}: ssa.OpNeq64,
+ opAndType{ONE, TUINT64}: ssa.OpNeq64,
+ opAndType{ONE, TINTER}: ssa.OpNeqInter,
+ opAndType{ONE, TSLICE}: ssa.OpNeqSlice,
+ opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
+ opAndType{ONE, TMAP}: ssa.OpNeqPtr,
+ opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
+ opAndType{ONE, TPTR}: ssa.OpNeqPtr,
+ opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
+ opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
+ opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
+ opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
+
+ opAndType{OLT, TINT8}: ssa.OpLess8,
+ opAndType{OLT, TUINT8}: ssa.OpLess8U,
+ opAndType{OLT, TINT16}: ssa.OpLess16,
+ opAndType{OLT, TUINT16}: ssa.OpLess16U,
+ opAndType{OLT, TINT32}: ssa.OpLess32,
+ opAndType{OLT, TUINT32}: ssa.OpLess32U,
+ opAndType{OLT, TINT64}: ssa.OpLess64,
+ opAndType{OLT, TUINT64}: ssa.OpLess64U,
+ opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
+ opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
+
+ opAndType{OLE, TINT8}: ssa.OpLeq8,
+ opAndType{OLE, TUINT8}: ssa.OpLeq8U,
+ opAndType{OLE, TINT16}: ssa.OpLeq16,
+ opAndType{OLE, TUINT16}: ssa.OpLeq16U,
+ opAndType{OLE, TINT32}: ssa.OpLeq32,
+ opAndType{OLE, TUINT32}: ssa.OpLeq32U,
+ opAndType{OLE, TINT64}: ssa.OpLeq64,
+ opAndType{OLE, TUINT64}: ssa.OpLeq64U,
+ opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
+ opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
+}
+
+func (s *state) concreteEtype(t *types.Type) types.EType {
+ e := t.Etype
+ switch e {
+ default:
+ return e
+ case TINT:
+ if s.config.PtrSize == 8 {
+ return TINT64
+ }
+ return TINT32
+ case TUINT:
+ if s.config.PtrSize == 8 {
+ return TUINT64
+ }
+ return TUINT32
+ case TUINTPTR:
+ if s.config.PtrSize == 8 {
+ return TUINT64
+ }
+ return TUINT32
+ }
+}
+
+func (s *state) ssaOp(op Op, t *types.Type) ssa.Op {
+ etype := s.concreteEtype(t)
+ x, ok := opToSSA[opAndType{op, etype}]
+ if !ok {
+ s.Fatalf("unhandled binary op %v %s", op, etype)
+ }
+ return x
+}
+
+func floatForComplex(t *types.Type) *types.Type {
+ switch t.Etype {
+ case TCOMPLEX64:
+ return types.Types[TFLOAT32]
+ case TCOMPLEX128:
+ return types.Types[TFLOAT64]
+ }
+ Fatalf("unexpected type: %v", t)
+ return nil
+}
+
+func complexForFloat(t *types.Type) *types.Type {
+ switch t.Etype {
+ case TFLOAT32:
+ return types.Types[TCOMPLEX64]
+ case TFLOAT64:
+ return types.Types[TCOMPLEX128]
+ }
+ Fatalf("unexpected type: %v", t)
+ return nil
+}
+
+type opAndTwoTypes struct {
+ op Op
+ etype1 types.EType
+ etype2 types.EType
+}
+
+type twoTypes struct {
+ etype1 types.EType
+ etype2 types.EType
+}
+
+type twoOpsAndType struct {
+ op1 ssa.Op
+ op2 ssa.Op
+ intermediateType types.EType
+}
+
+var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
+
+ twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
+ twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
+ twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
+ twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
+
+ twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
+ twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
+ twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
+ twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
+
+ twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
+ twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
+ twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
+ twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
+
+ twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
+ twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
+ twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
+ twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
+ // unsigned
+ twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
+ twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
+ twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
+ twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
+
+ twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
+ twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
+ twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
+ twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
+
+ twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
+ twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
+ twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
+ twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
+
+ twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
+ twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
+ twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
+ twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
+
+ // float
+ twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
+ twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpRound64F, ssa.OpCopy, TFLOAT64},
+ twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpRound32F, ssa.OpCopy, TFLOAT32},
+ 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 instructions 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,
+ opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
+ opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
+ opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
+ opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
+ opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
+ opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
+
+ opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
+ opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
+ opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
+ opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
+ opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
+ opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
+ opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
+ opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
+
+ opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
+ opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
+ opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
+ opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
+ opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
+ opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
+ opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
+ opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
+
+ opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
+ opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
+ opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
+ opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
+ opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
+ opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
+ opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
+ opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
+
+ opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
+ opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
+ opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
+ opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
+ opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
+ opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
+ opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
+ opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
+
+ opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
+ opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
+ opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
+ opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
+ opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
+ opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
+ opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
+ opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
+
+ opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
+ opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
+ opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
+ opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
+ opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
+ opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
+ opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
+ opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
+
+ opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
+ opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
+ opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
+ opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
+ opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
+ opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
+ opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
+ opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
+}
+
+func (s *state) ssaShiftOp(op Op, t *types.Type, u *types.Type) ssa.Op {
+ etype1 := s.concreteEtype(t)
+ etype2 := s.concreteEtype(u)
+ x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
+ if !ok {
+ s.Fatalf("unhandled shift op %v etype=%s/%s", op, etype1, etype2)
+ }
+ return x
+}
+
+// expr converts the expression n to ssa, adds it to s and returns the ssa result.
+func (s *state) expr(n *Node) *ssa.Value {
+ if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) {
+ // ONAMEs and named OLITERALs have the line number
+ // of the decl, not the use. See issue 14742.
+ s.pushLine(n.Pos)
+ defer s.popLine()
+ }
+
+ s.stmtList(n.Ninit)
+ switch n.Op {
+ case OBYTES2STRTMP:
+ slice := s.expr(n.Left)
+ ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice)
+ len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice)
+ return s.newValue2(ssa.OpStringMake, n.Type, ptr, len)
+ case OSTR2BYTESTMP:
+ str := s.expr(n.Left)
+ ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, str)
+ len := s.newValue1(ssa.OpStringLen, types.Types[TINT], str)
+ return s.newValue3(ssa.OpSliceMake, n.Type, ptr, len, len)
+ case OCFUNC:
+ aux := n.Left.Sym.Linksym()
+ return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
+ case ONAME:
+ if n.Class() == PFUNC {
+ // "value" of a function is the address of the function's closure
+ sym := funcsym(n.Sym).Linksym()
+ return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), sym, s.sb)
+ }
+ if s.canSSA(n) {
+ return s.variable(n, n.Type)
+ }
+ addr := s.addr(n)
+ return s.load(n.Type, addr)
+ case OCLOSUREVAR:
+ addr := s.addr(n)
+ return s.load(n.Type, addr)
+ case OLITERAL:
+ switch u := n.Val().U.(type) {
+ case *Mpint:
+ i := u.Int64()
+ switch n.Type.Size() {
+ case 1:
+ return s.constInt8(n.Type, int8(i))
+ case 2:
+ return s.constInt16(n.Type, int16(i))
+ case 4:
+ return s.constInt32(n.Type, int32(i))
+ case 8:
+ return s.constInt64(n.Type, i)
+ default:
+ s.Fatalf("bad integer size %d", n.Type.Size())
+ return nil
+ }
+ case string:
+ if u == "" {
+ return s.constEmptyString(n.Type)
+ }
+ return s.entryNewValue0A(ssa.OpConstString, n.Type, u)
+ case bool:
+ return s.constBool(u)
+ case *NilVal:
+ t := n.Type
+ switch {
+ case t.IsSlice():
+ return s.constSlice(t)
+ case t.IsInterface():
+ return s.constInterface(t)
+ default:
+ return s.constNil(t)
+ }
+ case *Mpflt:
+ switch n.Type.Size() {
+ case 4:
+ return s.constFloat32(n.Type, u.Float32())
+ case 8:
+ return s.constFloat64(n.Type, u.Float64())
+ default:
+ s.Fatalf("bad float size %d", n.Type.Size())
+ return nil
+ }
+ case *Mpcplx:
+ r := &u.Real
+ i := &u.Imag
+ switch n.Type.Size() {
+ case 8:
+ pt := types.Types[TFLOAT32]
+ return s.newValue2(ssa.OpComplexMake, n.Type,
+ s.constFloat32(pt, r.Float32()),
+ s.constFloat32(pt, i.Float32()))
+ case 16:
+ pt := types.Types[TFLOAT64]
+ return s.newValue2(ssa.OpComplexMake, n.Type,
+ s.constFloat64(pt, r.Float64()),
+ s.constFloat64(pt, i.Float64()))
+ default:
+ s.Fatalf("bad float size %d", n.Type.Size())
+ return nil
+ }
+
+ default:
+ s.Fatalf("unhandled OLITERAL %v", n.Val().Ctype())
+ return nil
+ }
+ case OCONVNOP:
+ to := n.Type
+ from := n.Left.Type
+
+ // Assume everything will work out, so set up our return value.
+ // Anything interesting that happens from here is a fatal.
+ x := s.expr(n.Left)
+
+ // Special case for not confusing GC and liveness.
+ // We don't want pointers accidentally classified
+ // as not-pointers or vice-versa because of copy
+ // elision.
+ if to.IsPtrShaped() != from.IsPtrShaped() {
+ return s.newValue2(ssa.OpConvert, to, x, s.mem())
+ }
+
+ v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
+
+ // CONVNOP closure
+ if to.Etype == TFUNC && from.IsPtrShaped() {
+ return v
+ }
+
+ // named <--> unnamed type or typed <--> untyped const
+ if from.Etype == to.Etype {
+ return v
+ }
+
+ // unsafe.Pointer <--> *T
+ if to.IsUnsafePtr() && from.IsPtrShaped() || from.IsUnsafePtr() && to.IsPtrShaped() {
+ return v
+ }
+
+ // map <--> *hmap
+ if to.Etype == TMAP && from.IsPtr() &&
+ to.MapType().Hmap == from.Elem() {
+ return v
+ }
+
+ dowidth(from)
+ dowidth(to)
+ if from.Width != to.Width {
+ s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
+ return nil
+ }
+ if etypesign(from.Etype) != etypesign(to.Etype) {
+ s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, from.Etype, to, to.Etype)
+ return nil
+ }
+
+ if instrumenting {
+ // These appear to be fine, but they fail the
+ // integer constraint below, so okay them here.
+ // Sample non-integer conversion: map[string]string -> *uint8
+ return v
+ }
+
+ if etypesign(from.Etype) == 0 {
+ s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
+ return nil
+ }
+
+ // integer, same width, same sign
+ return v
+
+ case OCONV:
+ x := s.expr(n.Left)
+ ft := n.Left.Type // from type
+ tt := n.Type // to type
+ if ft.IsBoolean() && tt.IsKind(TUINT8) {
+ // Bool -> uint8 is generated internally when indexing into runtime.staticbyte.
+ return s.newValue1(ssa.OpCopy, n.Type, x)
+ }
+ if ft.IsInteger() && tt.IsInteger() {
+ var op ssa.Op
+ if tt.Size() == ft.Size() {
+ op = ssa.OpCopy
+ } else if tt.Size() < ft.Size() {
+ // truncation
+ switch 10*ft.Size() + tt.Size() {
+ case 21:
+ op = ssa.OpTrunc16to8
+ case 41:
+ op = ssa.OpTrunc32to8
+ case 42:
+ op = ssa.OpTrunc32to16
+ case 81:
+ op = ssa.OpTrunc64to8
+ case 82:
+ op = ssa.OpTrunc64to16
+ case 84:
+ op = ssa.OpTrunc64to32
+ default:
+ s.Fatalf("weird integer truncation %v -> %v", ft, tt)
+ }
+ } else if ft.IsSigned() {
+ // sign extension
+ switch 10*ft.Size() + tt.Size() {
+ case 12:
+ op = ssa.OpSignExt8to16
+ case 14:
+ op = ssa.OpSignExt8to32
+ case 18:
+ op = ssa.OpSignExt8to64
+ case 24:
+ op = ssa.OpSignExt16to32
+ case 28:
+ op = ssa.OpSignExt16to64
+ case 48:
+ op = ssa.OpSignExt32to64
+ default:
+ s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
+ }
+ } else {
+ // zero extension
+ switch 10*ft.Size() + tt.Size() {
+ case 12:
+ op = ssa.OpZeroExt8to16
+ case 14:
+ op = ssa.OpZeroExt8to32
+ case 18:
+ op = ssa.OpZeroExt8to64
+ case 24:
+ op = ssa.OpZeroExt16to32
+ case 28:
+ op = ssa.OpZeroExt16to64
+ case 48:
+ op = ssa.OpZeroExt32to64
+ default:
+ s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
+ }
+ }
+ return s.newValue1(op, n.Type, x)
+ }
+
+ if ft.IsFloat() || tt.IsFloat() {
+ conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
+ if s.config.RegSize == 4 && thearch.LinkArch.Family != sys.MIPS && !s.softFloat {
+ if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
+ conv = conv1
+ }
+ }
+ if thearch.LinkArch.Family == sys.ARM64 || thearch.LinkArch.Family == sys.Wasm || thearch.LinkArch.Family == sys.S390X || s.softFloat {
+ if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
+ conv = conv1
+ }
+ }
+
+ if thearch.LinkArch.Family == sys.MIPS && !s.softFloat {
+ 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 %v -> %v", ft, tt)
+ }
+ op1, op2, it := conv.op1, conv.op2, conv.intermediateType
+
+ if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
+ // normal case, not tripping over unsigned 64
+ if op1 == ssa.OpCopy {
+ if op2 == ssa.OpCopy {
+ return x
+ }
+ return s.newValueOrSfCall1(op2, n.Type, x)
+ }
+ if op2 == ssa.OpCopy {
+ return s.newValueOrSfCall1(op1, n.Type, x)
+ }
+ return s.newValueOrSfCall1(op2, n.Type, s.newValueOrSfCall1(op1, types.Types[it], x))
+ }
+ // Tricky 64-bit unsigned cases.
+ if ft.IsInteger() {
+ // 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 %v -> %v", ft, tt)
+ }
+ // 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 %v -> %v", ft, tt)
+ return nil
+ }
+
+ if ft.IsComplex() && tt.IsComplex() {
+ var op ssa.Op
+ if ft.Size() == tt.Size() {
+ switch ft.Size() {
+ case 8:
+ op = ssa.OpRound32F
+ case 16:
+ op = ssa.OpRound64F
+ default:
+ s.Fatalf("weird complex conversion %v -> %v", ft, tt)
+ }
+ } else if ft.Size() == 8 && tt.Size() == 16 {
+ op = ssa.OpCvt32Fto64F
+ } else if ft.Size() == 16 && tt.Size() == 8 {
+ op = ssa.OpCvt64Fto32F
+ } else {
+ s.Fatalf("weird complex conversion %v -> %v", ft, tt)
+ }
+ ftp := floatForComplex(ft)
+ ttp := floatForComplex(tt)
+ return s.newValue2(ssa.OpComplexMake, tt,
+ s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
+ s.newValueOrSfCall1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
+ }
+
+ s.Fatalf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype)
+ return nil
+
+ case ODOTTYPE:
+ res, _ := s.dottype(n, false)
+ return res
+
+ // binary ops
+ case OLT, OEQ, ONE, OLE, OGE, OGT:
+ a := s.expr(n.Left)
+ b := s.expr(n.Right)
+ if n.Left.Type.IsComplex() {
+ pt := floatForComplex(n.Left.Type)
+ op := s.ssaOp(OEQ, pt)
+ r := s.newValueOrSfCall2(op, types.Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
+ i := s.newValueOrSfCall2(op, types.Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
+ c := s.newValue2(ssa.OpAndB, types.Types[TBOOL], r, i)
+ switch n.Op {
+ case OEQ:
+ return c
+ case ONE:
+ return s.newValue1(ssa.OpNot, types.Types[TBOOL], c)
+ default:
+ s.Fatalf("ordered complex compare %v", n.Op)
+ }
+ }
+
+ // Convert OGE and OGT into OLE and OLT.
+ op := n.Op
+ switch op {
+ case OGE:
+ op, a, b = OLE, b, a
+ case OGT:
+ op, a, b = OLT, b, a
+ }
+ if n.Left.Type.IsFloat() {
+ // float comparison
+ return s.newValueOrSfCall2(s.ssaOp(op, n.Left.Type), types.Types[TBOOL], a, b)
+ }
+ // integer comparison
+ return s.newValue2(s.ssaOp(op, n.Left.Type), types.Types[TBOOL], a, b)
+ case OMUL:
+ a := s.expr(n.Left)
+ b := s.expr(n.Right)
+ if n.Type.IsComplex() {
+ mulop := ssa.OpMul64F
+ addop := ssa.OpAdd64F
+ subop := ssa.OpSub64F
+ pt := floatForComplex(n.Type) // Could be Float32 or Float64
+ wt := types.Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
+
+ areal := s.newValue1(ssa.OpComplexReal, pt, a)
+ breal := s.newValue1(ssa.OpComplexReal, pt, b)
+ aimag := s.newValue1(ssa.OpComplexImag, pt, a)
+ bimag := s.newValue1(ssa.OpComplexImag, pt, b)
+
+ if pt != wt { // Widen for calculation
+ areal = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, areal)
+ breal = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, breal)
+ aimag = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, aimag)
+ bimag = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, bimag)
+ }
+
+ xreal := s.newValueOrSfCall2(subop, wt, s.newValueOrSfCall2(mulop, wt, areal, breal), s.newValueOrSfCall2(mulop, wt, aimag, bimag))
+ ximag := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, areal, bimag), s.newValueOrSfCall2(mulop, wt, aimag, breal))
+
+ if pt != wt { // Narrow to store back
+ xreal = s.newValueOrSfCall1(ssa.OpCvt64Fto32F, pt, xreal)
+ ximag = s.newValueOrSfCall1(ssa.OpCvt64Fto32F, pt, ximag)
+ }
+
+ return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
+ }
+
+ if n.Type.IsFloat() {
+ return s.newValueOrSfCall2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+ }
+
+ return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+
+ case ODIV:
+ a := s.expr(n.Left)
+ b := s.expr(n.Right)
+ if n.Type.IsComplex() {
+ // TODO this is not executed because the front-end substitutes a runtime call.
+ // That probably ought to change; with modest optimization the widen/narrow
+ // conversions could all be elided in larger expression trees.
+ mulop := ssa.OpMul64F
+ addop := ssa.OpAdd64F
+ subop := ssa.OpSub64F
+ divop := ssa.OpDiv64F
+ pt := floatForComplex(n.Type) // Could be Float32 or Float64
+ wt := types.Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
+
+ areal := s.newValue1(ssa.OpComplexReal, pt, a)
+ breal := s.newValue1(ssa.OpComplexReal, pt, b)
+ aimag := s.newValue1(ssa.OpComplexImag, pt, a)
+ bimag := s.newValue1(ssa.OpComplexImag, pt, b)
+
+ if pt != wt { // Widen for calculation
+ areal = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, areal)
+ breal = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, breal)
+ aimag = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, aimag)
+ bimag = s.newValueOrSfCall1(ssa.OpCvt32Fto64F, wt, bimag)
+ }
+
+ denom := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, breal, breal), s.newValueOrSfCall2(mulop, wt, bimag, bimag))
+ xreal := s.newValueOrSfCall2(addop, wt, s.newValueOrSfCall2(mulop, wt, areal, breal), s.newValueOrSfCall2(mulop, wt, aimag, bimag))
+ ximag := s.newValueOrSfCall2(subop, wt, s.newValueOrSfCall2(mulop, wt, aimag, breal), s.newValueOrSfCall2(mulop, wt, areal, bimag))
+
+ // TODO not sure if this is best done in wide precision or narrow
+ // Double-rounding might be an issue.
+ // Note that the pre-SSA implementation does the entire calculation
+ // in wide format, so wide is compatible.
+ xreal = s.newValueOrSfCall2(divop, wt, xreal, denom)
+ ximag = s.newValueOrSfCall2(divop, wt, ximag, denom)
+
+ if pt != wt { // Narrow to store back
+ xreal = s.newValueOrSfCall1(ssa.OpCvt64Fto32F, pt, xreal)
+ ximag = s.newValueOrSfCall1(ssa.OpCvt64Fto32F, pt, ximag)
+ }
+ return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
+ }
+ if n.Type.IsFloat() {
+ return s.newValueOrSfCall2(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)
+ return s.intDivide(n, a, b)
+ case OADD, OSUB:
+ a := s.expr(n.Left)
+ b := s.expr(n.Right)
+ if n.Type.IsComplex() {
+ pt := floatForComplex(n.Type)
+ op := s.ssaOp(n.Op, pt)
+ return s.newValue2(ssa.OpComplexMake, n.Type,
+ s.newValueOrSfCall2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
+ s.newValueOrSfCall2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
+ }
+ if n.Type.IsFloat() {
+ return s.newValueOrSfCall2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+ }
+ return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+ case OAND, OOR, OXOR:
+ a := s.expr(n.Left)
+ b := s.expr(n.Right)
+ return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+ case OANDNOT:
+ a := s.expr(n.Left)
+ b := s.expr(n.Right)
+ b = s.newValue1(s.ssaOp(OBITNOT, b.Type), b.Type, b)
+ return s.newValue2(s.ssaOp(OAND, n.Type), a.Type, a, b)
+ case OLSH, ORSH:
+ a := s.expr(n.Left)
+ b := s.expr(n.Right)
+ bt := b.Type
+ if bt.IsSigned() {
+ cmp := s.newValue2(s.ssaOp(OLE, bt), types.Types[TBOOL], s.zeroVal(bt), b)
+ s.check(cmp, panicshift)
+ bt = bt.ToUnsigned()
+ }
+ return s.newValue2(s.ssaShiftOp(n.Op, n.Type, bt), a.Type, a, b)
+ case OANDAND, OOROR:
+ // To implement OANDAND (and OOROR), we introduce a
+ // new temporary variable to hold the result. The
+ // variable is associated with the OANDAND node in the
+ // s.vars table (normally variables are only
+ // associated with ONAME nodes). We convert
+ // A && B
+ // to
+ // var = A
+ // if var {
+ // var = B
+ // }
+ // Using var in the subsequent block introduces the
+ // necessary phi variable.
+ el := s.expr(n.Left)
+ s.vars[n] = el
+
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(el)
+ // In theory, we should set b.Likely here based on context.
+ // However, gc only gives us likeliness hints
+ // in a single place, for plain OIF statements,
+ // and passing around context is finnicky, so don't bother for now.
+
+ bRight := s.f.NewBlock(ssa.BlockPlain)
+ bResult := s.f.NewBlock(ssa.BlockPlain)
+ if n.Op == OANDAND {
+ b.AddEdgeTo(bRight)
+ b.AddEdgeTo(bResult)
+ } else if n.Op == OOROR {
+ b.AddEdgeTo(bResult)
+ b.AddEdgeTo(bRight)
+ }
+
+ s.startBlock(bRight)
+ er := s.expr(n.Right)
+ s.vars[n] = er
+
+ b = s.endBlock()
+ b.AddEdgeTo(bResult)
+
+ s.startBlock(bResult)
+ return s.variable(n, types.Types[TBOOL])
+ case OCOMPLEX:
+ r := s.expr(n.Left)
+ i := s.expr(n.Right)
+ return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
+
+ // unary ops
+ case ONEG:
+ a := s.expr(n.Left)
+ if n.Type.IsComplex() {
+ tp := floatForComplex(n.Type)
+ negop := s.ssaOp(n.Op, tp)
+ return s.newValue2(ssa.OpComplexMake, n.Type,
+ s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
+ s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
+ }
+ return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
+ case ONOT, OBITNOT:
+ a := s.expr(n.Left)
+ return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
+ case OIMAG, OREAL:
+ a := s.expr(n.Left)
+ return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
+ case OPLUS:
+ return s.expr(n.Left)
+
+ case OADDR:
+ return s.addr(n.Left)
+
+ case ORESULT:
+ if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
+ // Do the old thing
+ addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
+ return s.rawLoad(n.Type, addr)
+ }
+ which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Xoffset)
+ if which == -1 {
+ // Do the old thing // TODO: Panic instead.
+ addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
+ return s.rawLoad(n.Type, addr)
+ }
+ if canSSAType(n.Type) {
+ return s.newValue1I(ssa.OpSelectN, n.Type, which, s.prevCall)
+ } else {
+ addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(n.Type), which, s.prevCall)
+ return s.rawLoad(n.Type, addr)
+ }
+
+ case ODEREF:
+ p := s.exprPtr(n.Left, n.Bounded(), n.Pos)
+ return s.load(n.Type, p)
+
+ case ODOT:
+ if n.Left.Op == OSTRUCTLIT {
+ // All literals with nonzero fields have already been
+ // rewritten during walk. Any that remain are just T{}
+ // or equivalents. Use the zero value.
+ if !isZero(n.Left) {
+ s.Fatalf("literal with nonzero value in SSA: %v", n.Left)
+ }
+ return s.zeroVal(n.Type)
+ }
+ // If n is addressable and can't be represented in
+ // SSA, then load just the selected field. This
+ // prevents false memory dependencies in race/msan
+ // instrumentation.
+ if islvalue(n) && !s.canSSA(n) {
+ p := s.addr(n)
+ return s.load(n.Type, p)
+ }
+ v := s.expr(n.Left)
+ return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
+
+ case ODOTPTR:
+ p := s.exprPtr(n.Left, n.Bounded(), n.Pos)
+ p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type), n.Xoffset, p)
+ return s.load(n.Type, p)
+
+ 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.Types[TUINT8], int64(int8(n.Left.StringVal()[n.Right.Int64Val()])))
+ }
+ a := s.expr(n.Left)
+ i := s.expr(n.Right)
+ len := s.newValue1(ssa.OpStringLen, types.Types[TINT], a)
+ i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
+ ptrtyp := s.f.Config.Types.BytePtr
+ ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
+ if Isconst(n.Right, CTINT) {
+ ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64Val(), ptr)
+ } else {
+ ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
+ }
+ return s.load(types.Types[TUINT8], ptr)
+ case n.Left.Type.IsSlice():
+ p := s.addr(n)
+ return s.load(n.Left.Type.Elem(), p)
+ case n.Left.Type.IsArray():
+ if canSSAType(n.Left.Type) {
+ // SSA can handle arrays of length at most 1.
+ bound := n.Left.Type.NumElem()
+ 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.Types[TINT], 0)
+ s.boundsCheck(z, z, ssa.BoundsIndex, false)
+ // The return value won't be live, return junk.
+ return s.newValue0(ssa.OpUnknown, n.Type)
+ }
+ len := s.constInt(types.Types[TINT], bound)
+ s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded()) // checks i == 0
+ return s.newValue1I(ssa.OpArraySelect, n.Type, 0, a)
+ }
+ p := s.addr(n)
+ return s.load(n.Left.Type.Elem(), p)
+ default:
+ s.Fatalf("bad type for index %v", n.Left.Type)
+ return nil
+ }
+
+ case OLEN, OCAP:
+ switch {
+ case n.Left.Type.IsSlice():
+ op := ssa.OpSliceLen
+ if n.Op == OCAP {
+ op = ssa.OpSliceCap
+ }
+ return s.newValue1(op, types.Types[TINT], s.expr(n.Left))
+ case n.Left.Type.IsString(): // string; not reachable for OCAP
+ return s.newValue1(ssa.OpStringLen, types.Types[TINT], s.expr(n.Left))
+ case n.Left.Type.IsMap(), n.Left.Type.IsChan():
+ return s.referenceTypeBuiltin(n, s.expr(n.Left))
+ default: // array
+ return s.constInt(types.Types[TINT], n.Left.Type.NumElem())
+ }
+
+ case OSPTR:
+ a := s.expr(n.Left)
+ if n.Left.Type.IsSlice() {
+ return s.newValue1(ssa.OpSlicePtr, n.Type, a)
+ } else {
+ return s.newValue1(ssa.OpStringPtr, n.Type, a)
+ }
+
+ case OITAB:
+ a := s.expr(n.Left)
+ return s.newValue1(ssa.OpITab, n.Type, a)
+
+ case 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)
+ return s.newValue2(ssa.OpIMake, n.Type, tab, data)
+
+ case OSLICEHEADER:
+ p := s.expr(n.Left)
+ l := s.expr(n.List.First())
+ c := s.expr(n.List.Second())
+ return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
+
+ case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
+ v := s.expr(n.Left)
+ var i, j, k *ssa.Value
+ low, high, max := n.SliceBounds()
+ if low != nil {
+ i = s.expr(low)
+ }
+ if high != nil {
+ j = s.expr(high)
+ }
+ if max != nil {
+ k = s.expr(max)
+ }
+ p, l, c := s.slice(v, i, j, k, n.Bounded())
+ return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
+
+ case OSLICESTR:
+ v := s.expr(n.Left)
+ var i, j *ssa.Value
+ low, high, _ := n.SliceBounds()
+ if low != nil {
+ i = s.expr(low)
+ }
+ if high != nil {
+ j = s.expr(high)
+ }
+ p, l, _ := s.slice(v, i, j, nil, n.Bounded())
+ return s.newValue2(ssa.OpStringMake, n.Type, p, l)
+
+ case OCALLFUNC:
+ if isIntrinsicCall(n) {
+ return s.intrinsicCall(n)
+ }
+ fallthrough
+
+ case OCALLINTER, OCALLMETH:
+ return s.callResult(n, callNormal)
+
+ case OGETG:
+ return s.newValue1(ssa.OpGetG, n.Type, s.mem())
+
+ case OAPPEND:
+ return s.append(n, false)
+
+ case OSTRUCTLIT, OARRAYLIT:
+ // All literals with nonzero fields have already been
+ // rewritten during walk. Any that remain are just T{}
+ // or equivalents. Use the zero value.
+ if !isZero(n) {
+ s.Fatalf("literal with nonzero value in SSA: %v", n)
+ }
+ return s.zeroVal(n.Type)
+
+ case ONEWOBJ:
+ if n.Type.Elem().Size() == 0 {
+ return s.newValue1A(ssa.OpAddr, n.Type, zerobaseSym, s.sb)
+ }
+ typ := s.expr(n.Left)
+ vv := s.rtcall(newobject, true, []*types.Type{n.Type}, typ)
+ return vv[0]
+
+ default:
+ s.Fatalf("unhandled expr %v", n.Op)
+ return nil
+ }
+}
+
+// append converts an OAPPEND node to SSA.
+// If inplace is false, it converts the OAPPEND expression n to an ssa.Value,
+// adds it to s, and returns the Value.
+// If inplace is true, it writes the result of the OAPPEND expression n
+// back to the slice being appended to, and returns nil.
+// inplace MUST be set to false if the slice can be SSA'd.
+func (s *state) append(n *Node, inplace bool) *ssa.Value {
+ // If inplace is false, process as expression "append(s, e1, e2, e3)":
+ //
+ // ptr, len, cap := s
+ // newlen := len + 3
+ // if newlen > cap {
+ // ptr, len, cap = growslice(s, newlen)
+ // newlen = len + 3 // recalculate to avoid a spill
+ // }
+ // // with write barriers, if needed:
+ // *(ptr+len) = e1
+ // *(ptr+len+1) = e2
+ // *(ptr+len+2) = e3
+ // return makeslice(ptr, newlen, cap)
+ //
+ //
+ // If inplace is true, process as statement "s = append(s, e1, e2, e3)":
+ //
+ // a := &s
+ // ptr, len, cap := s
+ // newlen := len + 3
+ // if uint(newlen) > uint(cap) {
+ // newptr, len, newcap = growslice(ptr, len, cap, newlen)
+ // vardef(a) // if necessary, advise liveness we are writing a new a
+ // *a.cap = newcap // write before ptr to avoid a spill
+ // *a.ptr = newptr // with write barrier
+ // }
+ // newlen = len + 3 // recalculate to avoid a spill
+ // *a.len = newlen
+ // // with write barriers, if needed:
+ // *(ptr+len) = e1
+ // *(ptr+len+1) = e2
+ // *(ptr+len+2) = e3
+
+ et := n.Type.Elem()
+ pt := types.NewPtr(et)
+
+ // Evaluate slice
+ sn := n.List.First() // the slice node is the first in the list
+
+ var slice, addr *ssa.Value
+ if inplace {
+ addr = s.addr(sn)
+ slice = s.load(n.Type, addr)
+ } else {
+ slice = s.expr(sn)
+ }
+
+ // Allocate new blocks
+ grow := s.f.NewBlock(ssa.BlockPlain)
+ assign := s.f.NewBlock(ssa.BlockPlain)
+
+ // Decide if we need to grow
+ nargs := int64(n.List.Len() - 1)
+ p := s.newValue1(ssa.OpSlicePtr, pt, slice)
+ l := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice)
+ c := s.newValue1(ssa.OpSliceCap, types.Types[TINT], slice)
+ nl := s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], l, s.constInt(types.Types[TINT], nargs))
+
+ cmp := s.newValue2(s.ssaOp(OLT, types.Types[TUINT]), types.Types[TBOOL], c, nl)
+ s.vars[&ptrVar] = p
+
+ if !inplace {
+ s.vars[&newlenVar] = nl
+ s.vars[&capVar] = c
+ } else {
+ s.vars[&lenVar] = l
+ }
+
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.Likely = ssa.BranchUnlikely
+ b.SetControl(cmp)
+ b.AddEdgeTo(grow)
+ b.AddEdgeTo(assign)
+
+ // Call growslice
+ s.startBlock(grow)
+ taddr := s.expr(n.Left)
+ r := s.rtcall(growslice, true, []*types.Type{pt, types.Types[TINT], types.Types[TINT]}, taddr, p, l, c, nl)
+
+ if inplace {
+ if sn.Op == ONAME && sn.Class() != PEXTERN {
+ // Tell liveness we're about to build a new slice
+ s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
+ }
+ capaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, sliceCapOffset, addr)
+ s.store(types.Types[TINT], capaddr, r[2])
+ s.store(pt, addr, r[0])
+ // load the value we just stored to avoid having to spill it
+ s.vars[&ptrVar] = s.load(pt, addr)
+ s.vars[&lenVar] = r[1] // avoid a spill in the fast path
+ } else {
+ s.vars[&ptrVar] = r[0]
+ s.vars[&newlenVar] = s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], r[1], s.constInt(types.Types[TINT], nargs))
+ s.vars[&capVar] = r[2]
+ }
+
+ b = s.endBlock()
+ b.AddEdgeTo(assign)
+
+ // assign new elements to slots
+ s.startBlock(assign)
+
+ if inplace {
+ l = s.variable(&lenVar, types.Types[TINT]) // generates phi for len
+ nl = s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], l, s.constInt(types.Types[TINT], nargs))
+ lenaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, sliceLenOffset, addr)
+ s.store(types.Types[TINT], lenaddr, nl)
+ }
+
+ // Evaluate args
+ type argRec struct {
+ // if store is true, we're appending the value v. If false, we're appending the
+ // value at *v.
+ v *ssa.Value
+ store bool
+ }
+ args := make([]argRec, 0, nargs)
+ for _, n := range n.List.Slice()[1:] {
+ if canSSAType(n.Type) {
+ args = append(args, argRec{v: s.expr(n), store: true})
+ } else {
+ v := s.addr(n)
+ args = append(args, argRec{v: v})
+ }
+ }
+
+ p = s.variable(&ptrVar, pt) // generates phi for ptr
+ if !inplace {
+ nl = s.variable(&newlenVar, types.Types[TINT]) // generates phi for nl
+ c = s.variable(&capVar, types.Types[TINT]) // generates phi for cap
+ }
+ p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
+ for i, arg := range args {
+ addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(types.Types[TINT], int64(i)))
+ if arg.store {
+ s.storeType(et, addr, arg.v, 0, true)
+ } else {
+ s.move(et, addr, arg.v)
+ }
+ }
+
+ delete(s.vars, &ptrVar)
+ if inplace {
+ delete(s.vars, &lenVar)
+ return nil
+ }
+ delete(s.vars, &newlenVar)
+ delete(s.vars, &capVar)
+ // make result
+ return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
+}
+
+// condBranch evaluates the boolean expression cond and branches to yes
+// if cond is true and no if cond is false.
+// This function is intended to handle && and || better than just calling
+// s.expr(cond) and branching on the result.
+func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
+ switch cond.Op {
+ case OANDAND:
+ mid := s.f.NewBlock(ssa.BlockPlain)
+ s.stmtList(cond.Ninit)
+ s.condBranch(cond.Left, mid, no, max8(likely, 0))
+ s.startBlock(mid)
+ s.condBranch(cond.Right, yes, no, likely)
+ return
+ // Note: if likely==1, then both recursive calls pass 1.
+ // If likely==-1, then we don't have enough information to decide
+ // whether the first branch is likely or not. So we pass 0 for
+ // the likeliness of the first branch.
+ // TODO: have the frontend give us branch prediction hints for
+ // OANDAND and OOROR nodes (if it ever has such info).
+ case OOROR:
+ mid := s.f.NewBlock(ssa.BlockPlain)
+ s.stmtList(cond.Ninit)
+ s.condBranch(cond.Left, yes, mid, min8(likely, 0))
+ s.startBlock(mid)
+ s.condBranch(cond.Right, yes, no, likely)
+ return
+ // Note: if likely==-1, then both recursive calls pass -1.
+ // If likely==1, then we don't have enough info to decide
+ // the likelihood of the first branch.
+ case ONOT:
+ s.stmtList(cond.Ninit)
+ s.condBranch(cond.Left, no, yes, -likely)
+ return
+ }
+ c := s.expr(cond)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(c)
+ b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
+ b.AddEdgeTo(yes)
+ b.AddEdgeTo(no)
+}
+
+type skipMask uint8
+
+const (
+ skipPtr skipMask = 1 << iota
+ skipLen
+ skipCap
+)
+
+// assign does left = right.
+// Right has already been evaluated to ssa, left has not.
+// If deref is true, then we do left = *right instead (and right has already been nil-checked).
+// If deref is true and right == nil, just do left = 0.
+// skip indicates assignments (at the top level) that can be avoided.
+func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask) {
+ if left.Op == ONAME && left.isBlank() {
+ return
+ }
+ t := left.Type
+ dowidth(t)
+ if s.canSSA(left) {
+ if deref {
+ 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.
+ // We need to build a new structure with the new value for the
+ // field we're assigning and the old values for the other fields.
+ // For instance:
+ // type T struct {a, b, c int}
+ // var T x
+ // x.b = 5
+ // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
+
+ // Grab information about the structure type.
+ t := left.Left.Type
+ nf := t.NumFields()
+ idx := fieldIdx(left)
+
+ // Grab old value of structure.
+ old := s.expr(left.Left)
+
+ // Make new structure.
+ new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
+
+ // Add fields as args.
+ for i := 0; i < nf; i++ {
+ if i == idx {
+ new.AddArg(right)
+ } else {
+ new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old))
+ }
+ }
+
+ // Recursively assign the new value we've made to the base of the dot op.
+ s.assign(left.Left, new, false, 0)
+ // TODO: do we need to update named values here?
+ return
+ }
+ if left.Op == OINDEX && left.Left.Type.IsArray() {
+ s.pushLine(left.Pos)
+ defer s.popLine()
+ // 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.Types[TINT], 0)
+ s.boundsCheck(z, z, ssa.BoundsIndex, false)
+ return
+ }
+ if n != 1 {
+ s.Fatalf("assigning to non-1-length array")
+ }
+ // Rewrite to a = [1]{v}
+ len := s.constInt(types.Types[TINT], 1)
+ s.boundsCheck(i, len, ssa.BoundsIndex, false) // checks i == 0
+ v := s.newValue1(ssa.OpArrayMake1, t, right)
+ s.assign(left.Left, v, false, 0)
+ return
+ }
+ // Update variable assignment.
+ s.vars[left] = right
+ s.addNamedValue(left, right)
+ return
+ }
+
+ // If this assignment clobbers an entire local variable, then emit
+ // OpVarDef so liveness analysis knows the variable is redefined.
+ if base := clobberBase(left); base.Op == ONAME && base.Class() != PEXTERN && skip == 0 {
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, base, s.mem(), !base.IsAutoTmp())
+ }
+
+ // Left is not ssa-able. Compute its address.
+ addr := s.addr(left)
+ if isReflectHeaderDataField(left) {
+ // Package unsafe's documentation says storing pointers into
+ // reflect.SliceHeader and reflect.StringHeader's Data fields
+ // is valid, even though they have type uintptr (#19168).
+ // Mark it pointer type to signal the writebarrier pass to
+ // insert a write barrier.
+ t = types.Types[TUNSAFEPTR]
+ }
+ if deref {
+ // Treat as a mem->mem move.
+ if right == nil {
+ s.zero(t, addr)
+ } else {
+ s.move(t, addr, right)
+ }
+ return
+ }
+ // Treat as a store.
+ s.storeType(t, addr, right, skip, !left.IsAutoTmp())
+}
+
+// zeroVal returns the zero value for type t.
+func (s *state) zeroVal(t *types.Type) *ssa.Value {
+ switch {
+ case t.IsInteger():
+ switch t.Size() {
+ case 1:
+ return s.constInt8(t, 0)
+ case 2:
+ return s.constInt16(t, 0)
+ case 4:
+ return s.constInt32(t, 0)
+ case 8:
+ return s.constInt64(t, 0)
+ default:
+ s.Fatalf("bad sized integer type %v", t)
+ }
+ case t.IsFloat():
+ switch t.Size() {
+ case 4:
+ return s.constFloat32(t, 0)
+ case 8:
+ return s.constFloat64(t, 0)
+ default:
+ s.Fatalf("bad sized float type %v", t)
+ }
+ case t.IsComplex():
+ switch t.Size() {
+ case 8:
+ z := s.constFloat32(types.Types[TFLOAT32], 0)
+ return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
+ case 16:
+ z := s.constFloat64(types.Types[TFLOAT64], 0)
+ return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
+ default:
+ s.Fatalf("bad sized complex type %v", t)
+ }
+
+ case t.IsString():
+ return s.constEmptyString(t)
+ case t.IsPtrShaped():
+ return s.constNil(t)
+ case t.IsBoolean():
+ return s.constBool(false)
+ case t.IsInterface():
+ return s.constInterface(t)
+ case t.IsSlice():
+ return s.constSlice(t)
+ case t.IsStruct():
+ n := t.NumFields()
+ v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
+ for i := 0; i < n; i++ {
+ v.AddArg(s.zeroVal(t.FieldType(i)))
+ }
+ 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.Fatalf("zero for type %v not implemented", t)
+ return nil
+}
+
+type callKind int8
+
+const (
+ callNormal callKind = iota
+ callDefer
+ callDeferStack
+ callGo
+)
+
+type sfRtCallDef struct {
+ rtfn *obj.LSym
+ rtype types.EType
+}
+
+var softFloatOps map[ssa.Op]sfRtCallDef
+
+func softfloatInit() {
+ // Some of these operations get transformed by sfcall.
+ softFloatOps = map[ssa.Op]sfRtCallDef{
+ ssa.OpAdd32F: sfRtCallDef{sysfunc("fadd32"), TFLOAT32},
+ ssa.OpAdd64F: sfRtCallDef{sysfunc("fadd64"), TFLOAT64},
+ ssa.OpSub32F: sfRtCallDef{sysfunc("fadd32"), TFLOAT32},
+ ssa.OpSub64F: sfRtCallDef{sysfunc("fadd64"), TFLOAT64},
+ ssa.OpMul32F: sfRtCallDef{sysfunc("fmul32"), TFLOAT32},
+ ssa.OpMul64F: sfRtCallDef{sysfunc("fmul64"), TFLOAT64},
+ ssa.OpDiv32F: sfRtCallDef{sysfunc("fdiv32"), TFLOAT32},
+ ssa.OpDiv64F: sfRtCallDef{sysfunc("fdiv64"), TFLOAT64},
+
+ ssa.OpEq64F: sfRtCallDef{sysfunc("feq64"), TBOOL},
+ ssa.OpEq32F: sfRtCallDef{sysfunc("feq32"), TBOOL},
+ ssa.OpNeq64F: sfRtCallDef{sysfunc("feq64"), TBOOL},
+ ssa.OpNeq32F: sfRtCallDef{sysfunc("feq32"), TBOOL},
+ ssa.OpLess64F: sfRtCallDef{sysfunc("fgt64"), TBOOL},
+ ssa.OpLess32F: sfRtCallDef{sysfunc("fgt32"), TBOOL},
+ ssa.OpLeq64F: sfRtCallDef{sysfunc("fge64"), TBOOL},
+ ssa.OpLeq32F: sfRtCallDef{sysfunc("fge32"), TBOOL},
+
+ ssa.OpCvt32to32F: sfRtCallDef{sysfunc("fint32to32"), TFLOAT32},
+ ssa.OpCvt32Fto32: sfRtCallDef{sysfunc("f32toint32"), TINT32},
+ ssa.OpCvt64to32F: sfRtCallDef{sysfunc("fint64to32"), TFLOAT32},
+ ssa.OpCvt32Fto64: sfRtCallDef{sysfunc("f32toint64"), TINT64},
+ ssa.OpCvt64Uto32F: sfRtCallDef{sysfunc("fuint64to32"), TFLOAT32},
+ ssa.OpCvt32Fto64U: sfRtCallDef{sysfunc("f32touint64"), TUINT64},
+ ssa.OpCvt32to64F: sfRtCallDef{sysfunc("fint32to64"), TFLOAT64},
+ ssa.OpCvt64Fto32: sfRtCallDef{sysfunc("f64toint32"), TINT32},
+ ssa.OpCvt64to64F: sfRtCallDef{sysfunc("fint64to64"), TFLOAT64},
+ ssa.OpCvt64Fto64: sfRtCallDef{sysfunc("f64toint64"), TINT64},
+ ssa.OpCvt64Uto64F: sfRtCallDef{sysfunc("fuint64to64"), TFLOAT64},
+ ssa.OpCvt64Fto64U: sfRtCallDef{sysfunc("f64touint64"), TUINT64},
+ ssa.OpCvt32Fto64F: sfRtCallDef{sysfunc("f32to64"), TFLOAT64},
+ ssa.OpCvt64Fto32F: sfRtCallDef{sysfunc("f64to32"), TFLOAT32},
+ }
+}
+
+// TODO: do not emit sfcall if operation can be optimized to constant in later
+// opt phase
+func (s *state) sfcall(op ssa.Op, args ...*ssa.Value) (*ssa.Value, bool) {
+ if callDef, ok := softFloatOps[op]; ok {
+ switch op {
+ case ssa.OpLess32F,
+ ssa.OpLess64F,
+ ssa.OpLeq32F,
+ ssa.OpLeq64F:
+ args[0], args[1] = args[1], args[0]
+ case ssa.OpSub32F,
+ ssa.OpSub64F:
+ args[1] = s.newValue1(s.ssaOp(ONEG, types.Types[callDef.rtype]), args[1].Type, args[1])
+ }
+
+ result := s.rtcall(callDef.rtfn, true, []*types.Type{types.Types[callDef.rtype]}, args...)[0]
+ if op == ssa.OpNeq32F || op == ssa.OpNeq64F {
+ result = s.newValue1(ssa.OpNot, result.Type, result)
+ }
+ return result, true
+ }
+ return nil, false
+}
+
+var intrinsics map[intrinsicKey]intrinsicBuilder
+
+// An intrinsicBuilder converts a call node n into an ssa value that
+// implements that call as an intrinsic. args is a list of arguments to the func.
+type intrinsicBuilder func(s *state, n *Node, args []*ssa.Value) *ssa.Value
+
+type intrinsicKey struct {
+ arch *sys.Arch
+ pkg string
+ fn string
+}
+
+func init() {
+ intrinsics = map[intrinsicKey]intrinsicBuilder{}
+
+ var all []*sys.Arch
+ var p4 []*sys.Arch
+ var p8 []*sys.Arch
+ var lwatomics []*sys.Arch
+ for _, a := range &sys.Archs {
+ all = append(all, a)
+ if a.PtrSize == 4 {
+ p4 = append(p4, a)
+ } else {
+ p8 = append(p8, a)
+ }
+ if a.Family != sys.PPC64 {
+ lwatomics = append(lwatomics, a)
+ }
+ }
+
+ // add adds the intrinsic b for pkg.fn for the given list of architectures.
+ add := func(pkg, fn string, b intrinsicBuilder, archs ...*sys.Arch) {
+ for _, a := range archs {
+ intrinsics[intrinsicKey{a, pkg, fn}] = b
+ }
+ }
+ // addF does the same as add but operates on architecture families.
+ addF := func(pkg, fn string, b intrinsicBuilder, archFamilies ...sys.ArchFamily) {
+ m := 0
+ for _, f := range archFamilies {
+ if f >= 32 {
+ panic("too many architecture families")
+ }
+ m |= 1 << uint(f)
+ }
+ for _, a := range all {
+ if m>>uint(a.Family)&1 != 0 {
+ intrinsics[intrinsicKey{a, pkg, fn}] = b
+ }
+ }
+ }
+ // alias defines pkg.fn = pkg2.fn2 for all architectures in archs for which pkg2.fn2 exists.
+ alias := func(pkg, fn, pkg2, fn2 string, archs ...*sys.Arch) {
+ aliased := false
+ for _, a := range archs {
+ if b, ok := intrinsics[intrinsicKey{a, pkg2, fn2}]; ok {
+ intrinsics[intrinsicKey{a, pkg, fn}] = b
+ aliased = true
+ }
+ }
+ if !aliased {
+ panic(fmt.Sprintf("attempted to alias undefined intrinsic: %s.%s", pkg, fn))
+ }
+ }
+
+ /******** runtime ********/
+ if !instrumenting {
+ add("runtime", "slicebytetostringtmp",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ // Compiler frontend optimizations emit OBYTES2STRTMP nodes
+ // for the backend instead of slicebytetostringtmp calls
+ // when not instrumenting.
+ return s.newValue2(ssa.OpStringMake, n.Type, args[0], args[1])
+ },
+ all...)
+ }
+ addF("runtime/internal/math", "MulUintptr",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if s.config.PtrSize == 4 {
+ return s.newValue2(ssa.OpMul32uover, types.NewTuple(types.Types[TUINT], types.Types[TUINT]), args[0], args[1])
+ }
+ return s.newValue2(ssa.OpMul64uover, types.NewTuple(types.Types[TUINT], types.Types[TUINT]), args[0], args[1])
+ },
+ sys.AMD64, sys.I386, sys.MIPS64)
+ add("runtime", "KeepAlive",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ data := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, args[0])
+ s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, types.TypeMem, data, s.mem())
+ return nil
+ },
+ all...)
+ add("runtime", "getclosureptr",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue0(ssa.OpGetClosurePtr, s.f.Config.Types.Uintptr)
+ },
+ all...)
+
+ add("runtime", "getcallerpc",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue0(ssa.OpGetCallerPC, s.f.Config.Types.Uintptr)
+ },
+ all...)
+
+ add("runtime", "getcallersp",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue0(ssa.OpGetCallerSP, s.f.Config.Types.Uintptr)
+ },
+ all...)
+
+ /******** runtime/internal/sys ********/
+ addF("runtime/internal/sys", "Ctz32",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz32, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+ addF("runtime/internal/sys", "Ctz64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz64, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64)
+ addF("runtime/internal/sys", "Bswap32",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBswap32, types.Types[TUINT32], args[0])
+ },
+ sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
+ addF("runtime/internal/sys", "Bswap64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBswap64, types.Types[TUINT64], args[0])
+ },
+ sys.AMD64, sys.ARM64, sys.ARM, sys.S390X)
+
+ /******** runtime/internal/atomic ********/
+ addF("runtime/internal/atomic", "Load",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoad32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "Load8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoad8, types.NewTuple(types.Types[TUINT8], types.TypeMem), args[0], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT8], v)
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "Load64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoad64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "LoadAcq",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoadAcq32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ },
+ sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "LoadAcq64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoadAcq64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ },
+ sys.PPC64)
+ addF("runtime/internal/atomic", "Loadp",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, s.f.Config.Types.BytePtr, v)
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+
+ addF("runtime/internal/atomic", "Store",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore32, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "Store8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore8, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "Store64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore64, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "StorepNoWB",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStorePtrNoWB, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "StoreRel",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStoreRel32, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "StoreRel64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStoreRel64, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.PPC64)
+
+ addF("runtime/internal/atomic", "Xchg",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue3(ssa.OpAtomicExchange32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], args[1], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ },
+ sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "Xchg64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue3(ssa.OpAtomicExchange64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ },
+ sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+
+ type atomicOpEmitter func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType)
+
+ makeAtomicGuardedIntrinsicARM64 := func(op0, op1 ssa.Op, typ, rtyp types.EType, emit atomicOpEmitter) intrinsicBuilder {
+
+ return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ // Target Atomic feature is identified by dynamic detection
+ addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), arm64HasATOMICS, s.sb)
+ v := s.load(types.Types[TBOOL], addr)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(v)
+ bTrue := s.f.NewBlock(ssa.BlockPlain)
+ bFalse := s.f.NewBlock(ssa.BlockPlain)
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(bTrue)
+ b.AddEdgeTo(bFalse)
+ b.Likely = ssa.BranchLikely
+
+ // We have atomic instructions - use it directly.
+ s.startBlock(bTrue)
+ emit(s, n, args, op1, typ)
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Use original instruction sequence.
+ s.startBlock(bFalse)
+ emit(s, n, args, op0, typ)
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Merge results.
+ s.startBlock(bEnd)
+ if rtyp == TNIL {
+ return nil
+ } else {
+ return s.variable(n, types.Types[rtyp])
+ }
+ }
+ }
+
+ atomicXchgXaddEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
+ v := s.newValue3(op, types.NewTuple(types.Types[typ], types.TypeMem), args[0], args[1], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[typ], v)
+ }
+ addF("runtime/internal/atomic", "Xchg",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicExchange32, ssa.OpAtomicExchange32Variant, TUINT32, TUINT32, atomicXchgXaddEmitterARM64),
+ sys.ARM64)
+ addF("runtime/internal/atomic", "Xchg64",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicExchange64, ssa.OpAtomicExchange64Variant, TUINT64, TUINT64, atomicXchgXaddEmitterARM64),
+ sys.ARM64)
+
+ addF("runtime/internal/atomic", "Xadd",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue3(ssa.OpAtomicAdd32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], args[1], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
+ },
+ sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "Xadd64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue3(ssa.OpAtomicAdd64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ },
+ sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+
+ addF("runtime/internal/atomic", "Xadd",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, TUINT32, TUINT32, atomicXchgXaddEmitterARM64),
+ sys.ARM64)
+ addF("runtime/internal/atomic", "Xadd64",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, TUINT64, TUINT64, atomicXchgXaddEmitterARM64),
+ sys.ARM64)
+
+ addF("runtime/internal/atomic", "Cas",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
+ },
+ sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "Cas64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue4(ssa.OpAtomicCompareAndSwap64, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
+ },
+ sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
+ addF("runtime/internal/atomic", "CasRel",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
+ },
+ sys.PPC64)
+
+ atomicCasEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
+ v := s.newValue4(op, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[typ], v)
+ }
+
+ addF("runtime/internal/atomic", "Cas",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicCompareAndSwap32, ssa.OpAtomicCompareAndSwap32Variant, TUINT32, TBOOL, atomicCasEmitterARM64),
+ sys.ARM64)
+ addF("runtime/internal/atomic", "Cas64",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicCompareAndSwap64, ssa.OpAtomicCompareAndSwap64Variant, TUINT64, TBOOL, atomicCasEmitterARM64),
+ sys.ARM64)
+
+ addF("runtime/internal/atomic", "And8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd8, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "And",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd32, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "Or8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "Or",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr32, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
+
+ atomicAndOrEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
+ s.vars[&memVar] = s.newValue3(op, types.TypeMem, args[0], args[1], s.mem())
+ }
+
+ addF("runtime/internal/atomic", "And8",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAnd8, ssa.OpAtomicAnd8Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
+ sys.ARM64)
+ addF("runtime/internal/atomic", "And",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAnd32, ssa.OpAtomicAnd32Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
+ sys.ARM64)
+ addF("runtime/internal/atomic", "Or8",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicOr8, ssa.OpAtomicOr8Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
+ sys.ARM64)
+ addF("runtime/internal/atomic", "Or",
+ makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicOr32, ssa.OpAtomicOr32Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
+ sys.ARM64)
+
+ alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...)
+ alias("runtime/internal/atomic", "Xaddint64", "runtime/internal/atomic", "Xadd64", all...)
+ alias("runtime/internal/atomic", "Loaduint", "runtime/internal/atomic", "Load", p4...)
+ alias("runtime/internal/atomic", "Loaduint", "runtime/internal/atomic", "Load64", p8...)
+ alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...)
+ alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...)
+ alias("runtime/internal/atomic", "LoadAcq", "runtime/internal/atomic", "Load", lwatomics...)
+ alias("runtime/internal/atomic", "LoadAcq64", "runtime/internal/atomic", "Load64", lwatomics...)
+ alias("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq", p4...)
+ alias("sync", "runtime_LoadAcquintptr", "runtime/internal/atomic", "LoadAcq", p4...) // linknamed
+ alias("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...)
+ alias("sync", "runtime_LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...) // linknamed
+ alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...)
+ alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...)
+ alias("runtime/internal/atomic", "StoreRel", "runtime/internal/atomic", "Store", lwatomics...)
+ alias("runtime/internal/atomic", "StoreRel64", "runtime/internal/atomic", "Store64", lwatomics...)
+ alias("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel", p4...)
+ alias("sync", "runtime_StoreReluintptr", "runtime/internal/atomic", "StoreRel", p4...) // linknamed
+ alias("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...)
+ alias("sync", "runtime_StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...) // linknamed
+ alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...)
+ alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...)
+ alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...)
+ alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd64", p8...)
+ alias("runtime/internal/atomic", "Casuintptr", "runtime/internal/atomic", "Cas", p4...)
+ alias("runtime/internal/atomic", "Casuintptr", "runtime/internal/atomic", "Cas64", p8...)
+ alias("runtime/internal/atomic", "Casp1", "runtime/internal/atomic", "Cas", p4...)
+ alias("runtime/internal/atomic", "Casp1", "runtime/internal/atomic", "Cas64", p8...)
+ alias("runtime/internal/atomic", "CasRel", "runtime/internal/atomic", "Cas", lwatomics...)
+
+ /******** math ********/
+ addF("math", "Sqrt",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpSqrt, types.Types[TFLOAT64], args[0])
+ },
+ sys.I386, sys.AMD64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X, sys.Wasm)
+ addF("math", "Trunc",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpTrunc, types.Types[TFLOAT64], args[0])
+ },
+ sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
+ addF("math", "Ceil",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCeil, types.Types[TFLOAT64], args[0])
+ },
+ sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
+ addF("math", "Floor",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpFloor, types.Types[TFLOAT64], args[0])
+ },
+ sys.ARM64, sys.PPC64, sys.S390X, sys.Wasm)
+ addF("math", "Round",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpRound, types.Types[TFLOAT64], args[0])
+ },
+ sys.ARM64, sys.PPC64, sys.S390X)
+ addF("math", "RoundToEven",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpRoundToEven, types.Types[TFLOAT64], args[0])
+ },
+ sys.ARM64, sys.S390X, sys.Wasm)
+ addF("math", "Abs",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpAbs, types.Types[TFLOAT64], args[0])
+ },
+ sys.ARM64, sys.ARM, sys.PPC64, sys.Wasm)
+ addF("math", "Copysign",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpCopysign, types.Types[TFLOAT64], args[0], args[1])
+ },
+ sys.PPC64, sys.Wasm)
+ addF("math", "FMA",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue3(ssa.OpFMA, types.Types[TFLOAT64], args[0], args[1], args[2])
+ },
+ sys.ARM64, sys.PPC64, sys.S390X)
+ addF("math", "FMA",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if !s.config.UseFMA {
+ s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
+ return s.variable(n, types.Types[TFLOAT64])
+ }
+ v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[TBOOL], x86HasFMA)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(v)
+ bTrue := s.f.NewBlock(ssa.BlockPlain)
+ bFalse := s.f.NewBlock(ssa.BlockPlain)
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(bTrue)
+ b.AddEdgeTo(bFalse)
+ b.Likely = ssa.BranchLikely // >= haswell cpus are common
+
+ // We have the intrinsic - use it directly.
+ s.startBlock(bTrue)
+ s.vars[n] = s.newValue3(ssa.OpFMA, types.Types[TFLOAT64], args[0], args[1], args[2])
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Call the pure Go version.
+ s.startBlock(bFalse)
+ s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Merge results.
+ s.startBlock(bEnd)
+ return s.variable(n, types.Types[TFLOAT64])
+ },
+ sys.AMD64)
+ addF("math", "FMA",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if !s.config.UseFMA {
+ s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
+ return s.variable(n, types.Types[TFLOAT64])
+ }
+ addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), armHasVFPv4, s.sb)
+ v := s.load(types.Types[TBOOL], addr)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(v)
+ bTrue := s.f.NewBlock(ssa.BlockPlain)
+ bFalse := s.f.NewBlock(ssa.BlockPlain)
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(bTrue)
+ b.AddEdgeTo(bFalse)
+ b.Likely = ssa.BranchLikely
+
+ // We have the intrinsic - use it directly.
+ s.startBlock(bTrue)
+ s.vars[n] = s.newValue3(ssa.OpFMA, types.Types[TFLOAT64], args[0], args[1], args[2])
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Call the pure Go version.
+ s.startBlock(bFalse)
+ s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Merge results.
+ s.startBlock(bEnd)
+ return s.variable(n, types.Types[TFLOAT64])
+ },
+ sys.ARM)
+
+ makeRoundAMD64 := func(op ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[TBOOL], x86HasSSE41)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(v)
+ bTrue := s.f.NewBlock(ssa.BlockPlain)
+ bFalse := s.f.NewBlock(ssa.BlockPlain)
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(bTrue)
+ b.AddEdgeTo(bFalse)
+ b.Likely = ssa.BranchLikely // most machines have sse4.1 nowadays
+
+ // We have the intrinsic - use it directly.
+ s.startBlock(bTrue)
+ s.vars[n] = s.newValue1(op, types.Types[TFLOAT64], args[0])
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Call the pure Go version.
+ s.startBlock(bFalse)
+ s.vars[n] = s.callResult(n, callNormal) // types.Types[TFLOAT64]
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Merge results.
+ s.startBlock(bEnd)
+ return s.variable(n, types.Types[TFLOAT64])
+ }
+ }
+ addF("math", "RoundToEven",
+ makeRoundAMD64(ssa.OpRoundToEven),
+ sys.AMD64)
+ addF("math", "Floor",
+ makeRoundAMD64(ssa.OpFloor),
+ sys.AMD64)
+ addF("math", "Ceil",
+ makeRoundAMD64(ssa.OpCeil),
+ sys.AMD64)
+ addF("math", "Trunc",
+ makeRoundAMD64(ssa.OpTrunc),
+ sys.AMD64)
+
+ /******** math/bits ********/
+ addF("math/bits", "TrailingZeros64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz64, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
+ addF("math/bits", "TrailingZeros32",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz32, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
+ addF("math/bits", "TrailingZeros16",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ x := s.newValue1(ssa.OpZeroExt16to32, types.Types[TUINT32], args[0])
+ c := s.constInt32(types.Types[TUINT32], 1<<16)
+ y := s.newValue2(ssa.OpOr32, types.Types[TUINT32], x, c)
+ return s.newValue1(ssa.OpCtz32, types.Types[TINT], y)
+ },
+ sys.MIPS)
+ addF("math/bits", "TrailingZeros16",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz16, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.I386, sys.ARM, sys.ARM64, sys.Wasm)
+ addF("math/bits", "TrailingZeros16",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ x := s.newValue1(ssa.OpZeroExt16to64, types.Types[TUINT64], args[0])
+ c := s.constInt64(types.Types[TUINT64], 1<<16)
+ y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c)
+ return s.newValue1(ssa.OpCtz64, types.Types[TINT], y)
+ },
+ sys.S390X, sys.PPC64)
+ addF("math/bits", "TrailingZeros8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0])
+ c := s.constInt32(types.Types[TUINT32], 1<<8)
+ y := s.newValue2(ssa.OpOr32, types.Types[TUINT32], x, c)
+ return s.newValue1(ssa.OpCtz32, types.Types[TINT], y)
+ },
+ sys.MIPS)
+ addF("math/bits", "TrailingZeros8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpCtz8, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.ARM, sys.ARM64, sys.Wasm)
+ addF("math/bits", "TrailingZeros8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ x := s.newValue1(ssa.OpZeroExt8to64, types.Types[TUINT64], args[0])
+ c := s.constInt64(types.Types[TUINT64], 1<<8)
+ y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c)
+ return s.newValue1(ssa.OpCtz64, types.Types[TINT], y)
+ },
+ sys.S390X)
+ alias("math/bits", "ReverseBytes64", "runtime/internal/sys", "Bswap64", all...)
+ alias("math/bits", "ReverseBytes32", "runtime/internal/sys", "Bswap32", all...)
+ // ReverseBytes inlines correctly, no need to intrinsify it.
+ // ReverseBytes16 lowers to a rotate, no need for anything special here.
+ addF("math/bits", "Len64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitLen64, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
+ addF("math/bits", "Len32",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.ARM64)
+ addF("math/bits", "Len32",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if s.config.PtrSize == 4 {
+ return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0])
+ }
+ x := s.newValue1(ssa.OpZeroExt32to64, types.Types[TUINT64], args[0])
+ return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+ },
+ sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
+ addF("math/bits", "Len16",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if s.config.PtrSize == 4 {
+ x := s.newValue1(ssa.OpZeroExt16to32, types.Types[TUINT32], args[0])
+ return s.newValue1(ssa.OpBitLen32, types.Types[TINT], x)
+ }
+ x := s.newValue1(ssa.OpZeroExt16to64, types.Types[TUINT64], args[0])
+ return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+ },
+ sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
+ addF("math/bits", "Len16",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitLen16, types.Types[TINT], args[0])
+ },
+ sys.AMD64)
+ addF("math/bits", "Len8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if s.config.PtrSize == 4 {
+ x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0])
+ return s.newValue1(ssa.OpBitLen32, types.Types[TINT], x)
+ }
+ x := s.newValue1(ssa.OpZeroExt8to64, types.Types[TUINT64], args[0])
+ return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x)
+ },
+ sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
+ addF("math/bits", "Len8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitLen8, types.Types[TINT], args[0])
+ },
+ sys.AMD64)
+ addF("math/bits", "Len",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if s.config.PtrSize == 4 {
+ return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0])
+ }
+ return s.newValue1(ssa.OpBitLen64, types.Types[TINT], args[0])
+ },
+ sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64, sys.Wasm)
+ // LeadingZeros is handled because it trivially calls Len.
+ addF("math/bits", "Reverse64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0])
+ },
+ sys.ARM64)
+ addF("math/bits", "Reverse32",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitRev32, types.Types[TINT], args[0])
+ },
+ sys.ARM64)
+ addF("math/bits", "Reverse16",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitRev16, types.Types[TINT], args[0])
+ },
+ sys.ARM64)
+ addF("math/bits", "Reverse8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpBitRev8, types.Types[TINT], args[0])
+ },
+ sys.ARM64)
+ addF("math/bits", "Reverse",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ if s.config.PtrSize == 4 {
+ return s.newValue1(ssa.OpBitRev32, types.Types[TINT], args[0])
+ }
+ return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0])
+ },
+ sys.ARM64)
+ addF("math/bits", "RotateLeft8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpRotateLeft8, types.Types[TUINT8], args[0], args[1])
+ },
+ sys.AMD64)
+ addF("math/bits", "RotateLeft16",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpRotateLeft16, types.Types[TUINT16], args[0], args[1])
+ },
+ sys.AMD64)
+ addF("math/bits", "RotateLeft32",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpRotateLeft32, types.Types[TUINT32], args[0], args[1])
+ },
+ sys.AMD64, sys.ARM, sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
+ addF("math/bits", "RotateLeft64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpRotateLeft64, types.Types[TUINT64], args[0], args[1])
+ },
+ sys.AMD64, sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
+ alias("math/bits", "RotateLeft", "math/bits", "RotateLeft64", p8...)
+
+ makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.entryNewValue0A(ssa.OpHasCPUFeature, types.Types[TBOOL], x86HasPOPCNT)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(v)
+ bTrue := s.f.NewBlock(ssa.BlockPlain)
+ bFalse := s.f.NewBlock(ssa.BlockPlain)
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(bTrue)
+ b.AddEdgeTo(bFalse)
+ b.Likely = ssa.BranchLikely // most machines have popcnt nowadays
+
+ // We have the intrinsic - use it directly.
+ s.startBlock(bTrue)
+ op := op64
+ if s.config.PtrSize == 4 {
+ op = op32
+ }
+ s.vars[n] = s.newValue1(op, types.Types[TINT], args[0])
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Call the pure Go version.
+ s.startBlock(bFalse)
+ s.vars[n] = s.callResult(n, callNormal) // types.Types[TINT]
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Merge results.
+ s.startBlock(bEnd)
+ return s.variable(n, types.Types[TINT])
+ }
+ }
+ addF("math/bits", "OnesCount64",
+ makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount64),
+ sys.AMD64)
+ addF("math/bits", "OnesCount64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpPopCount64, types.Types[TINT], args[0])
+ },
+ sys.PPC64, sys.ARM64, sys.S390X, sys.Wasm)
+ addF("math/bits", "OnesCount32",
+ makeOnesCountAMD64(ssa.OpPopCount32, ssa.OpPopCount32),
+ sys.AMD64)
+ addF("math/bits", "OnesCount32",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpPopCount32, types.Types[TINT], args[0])
+ },
+ sys.PPC64, sys.ARM64, sys.S390X, sys.Wasm)
+ addF("math/bits", "OnesCount16",
+ makeOnesCountAMD64(ssa.OpPopCount16, ssa.OpPopCount16),
+ sys.AMD64)
+ addF("math/bits", "OnesCount16",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpPopCount16, types.Types[TINT], args[0])
+ },
+ sys.ARM64, sys.S390X, sys.PPC64, sys.Wasm)
+ addF("math/bits", "OnesCount8",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue1(ssa.OpPopCount8, types.Types[TINT], args[0])
+ },
+ sys.S390X, sys.PPC64, sys.Wasm)
+ addF("math/bits", "OnesCount",
+ makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32),
+ sys.AMD64)
+ addF("math/bits", "Mul64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1])
+ },
+ sys.AMD64, sys.ARM64, sys.PPC64, sys.S390X, sys.MIPS64)
+ alias("math/bits", "Mul", "math/bits", "Mul64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchS390X, sys.ArchMIPS64, sys.ArchMIPS64LE)
+ addF("math/bits", "Add64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue3(ssa.OpAdd64carry, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
+ },
+ sys.AMD64, sys.ARM64, sys.PPC64, sys.S390X)
+ alias("math/bits", "Add", "math/bits", "Add64", sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64, sys.ArchS390X)
+ addF("math/bits", "Sub64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue3(ssa.OpSub64borrow, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
+ },
+ sys.AMD64, sys.ARM64, sys.S390X)
+ alias("math/bits", "Sub", "math/bits", "Sub64", sys.ArchAMD64, sys.ArchARM64, sys.ArchS390X)
+ addF("math/bits", "Div64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ // check for divide-by-zero/overflow and panic with appropriate message
+ cmpZero := s.newValue2(s.ssaOp(ONE, types.Types[TUINT64]), types.Types[TBOOL], args[2], s.zeroVal(types.Types[TUINT64]))
+ s.check(cmpZero, panicdivide)
+ cmpOverflow := s.newValue2(s.ssaOp(OLT, types.Types[TUINT64]), types.Types[TBOOL], args[0], args[2])
+ s.check(cmpOverflow, panicoverflow)
+ return s.newValue3(ssa.OpDiv128u, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
+ },
+ sys.AMD64)
+ alias("math/bits", "Div", "math/bits", "Div64", sys.ArchAMD64)
+
+ alias("runtime/internal/sys", "Ctz8", "math/bits", "TrailingZeros8", all...)
+ alias("runtime/internal/sys", "TrailingZeros8", "math/bits", "TrailingZeros8", all...)
+ alias("runtime/internal/sys", "TrailingZeros64", "math/bits", "TrailingZeros64", all...)
+ alias("runtime/internal/sys", "Len8", "math/bits", "Len8", all...)
+ alias("runtime/internal/sys", "Len64", "math/bits", "Len64", all...)
+ alias("runtime/internal/sys", "OnesCount64", "math/bits", "OnesCount64", all...)
+
+ /******** sync/atomic ********/
+
+ // Note: these are disabled by flag_race in findIntrinsic below.
+ alias("sync/atomic", "LoadInt32", "runtime/internal/atomic", "Load", all...)
+ alias("sync/atomic", "LoadInt64", "runtime/internal/atomic", "Load64", all...)
+ alias("sync/atomic", "LoadPointer", "runtime/internal/atomic", "Loadp", all...)
+ alias("sync/atomic", "LoadUint32", "runtime/internal/atomic", "Load", all...)
+ alias("sync/atomic", "LoadUint64", "runtime/internal/atomic", "Load64", all...)
+ alias("sync/atomic", "LoadUintptr", "runtime/internal/atomic", "Load", p4...)
+ alias("sync/atomic", "LoadUintptr", "runtime/internal/atomic", "Load64", p8...)
+
+ alias("sync/atomic", "StoreInt32", "runtime/internal/atomic", "Store", all...)
+ alias("sync/atomic", "StoreInt64", "runtime/internal/atomic", "Store64", all...)
+ // Note: not StorePointer, that needs a write barrier. Same below for {CompareAnd}Swap.
+ alias("sync/atomic", "StoreUint32", "runtime/internal/atomic", "Store", all...)
+ alias("sync/atomic", "StoreUint64", "runtime/internal/atomic", "Store64", all...)
+ alias("sync/atomic", "StoreUintptr", "runtime/internal/atomic", "Store", p4...)
+ alias("sync/atomic", "StoreUintptr", "runtime/internal/atomic", "Store64", p8...)
+
+ alias("sync/atomic", "SwapInt32", "runtime/internal/atomic", "Xchg", all...)
+ alias("sync/atomic", "SwapInt64", "runtime/internal/atomic", "Xchg64", all...)
+ alias("sync/atomic", "SwapUint32", "runtime/internal/atomic", "Xchg", all...)
+ alias("sync/atomic", "SwapUint64", "runtime/internal/atomic", "Xchg64", all...)
+ alias("sync/atomic", "SwapUintptr", "runtime/internal/atomic", "Xchg", p4...)
+ alias("sync/atomic", "SwapUintptr", "runtime/internal/atomic", "Xchg64", p8...)
+
+ alias("sync/atomic", "CompareAndSwapInt32", "runtime/internal/atomic", "Cas", all...)
+ alias("sync/atomic", "CompareAndSwapInt64", "runtime/internal/atomic", "Cas64", all...)
+ alias("sync/atomic", "CompareAndSwapUint32", "runtime/internal/atomic", "Cas", all...)
+ alias("sync/atomic", "CompareAndSwapUint64", "runtime/internal/atomic", "Cas64", all...)
+ alias("sync/atomic", "CompareAndSwapUintptr", "runtime/internal/atomic", "Cas", p4...)
+ alias("sync/atomic", "CompareAndSwapUintptr", "runtime/internal/atomic", "Cas64", p8...)
+
+ alias("sync/atomic", "AddInt32", "runtime/internal/atomic", "Xadd", all...)
+ alias("sync/atomic", "AddInt64", "runtime/internal/atomic", "Xadd64", all...)
+ alias("sync/atomic", "AddUint32", "runtime/internal/atomic", "Xadd", all...)
+ alias("sync/atomic", "AddUint64", "runtime/internal/atomic", "Xadd64", all...)
+ alias("sync/atomic", "AddUintptr", "runtime/internal/atomic", "Xadd", p4...)
+ alias("sync/atomic", "AddUintptr", "runtime/internal/atomic", "Xadd64", p8...)
+
+ /******** math/big ********/
+ add("math/big", "mulWW",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1])
+ },
+ sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64LE, sys.ArchPPC64, sys.ArchS390X)
+}
+
+// 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 *types.Sym) intrinsicBuilder {
+ if sym == nil || sym.Pkg == nil {
+ return nil
+ }
+ pkg := sym.Pkg.Path
+ if sym.Pkg == localpkg {
+ pkg = myimportpath
+ }
+ if flag_race && pkg == "sync/atomic" {
+ // The race detector needs to be able to intercept these calls.
+ // We can't intrinsify them.
+ return nil
+ }
+ // Skip intrinsifying math functions (which may contain hard-float
+ // instructions) when soft-float
+ if thearch.SoftFloat && pkg == "math" {
+ return nil
+ }
+
+ fn := sym.Name
+ if ssa.IntrinsicsDisable {
+ if pkg == "runtime" && (fn == "getcallerpc" || fn == "getcallersp" || fn == "getclosureptr") {
+ // These runtime functions don't have definitions, must be intrinsics.
+ } else {
+ return nil
+ }
+ }
+ return intrinsics[intrinsicKey{thearch.LinkArch.Arch, pkg, fn}]
+}
+
+func isIntrinsicCall(n *Node) bool {
+ if n == nil || n.Left == nil {
+ return false
+ }
+ return findIntrinsic(n.Left.Sym) != nil
+}
+
+// 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.Pos, "intrinsic substitution for %v with %s", n.Left.Sym.Name, x.LongString())
+ }
+ return v
+}
+
+// intrinsicArgs extracts args from n, evaluates them to SSA values, and returns them.
+func (s *state) intrinsicArgs(n *Node) []*ssa.Value {
+ // Construct map of temps; see comments in s.call about the structure of n.
+ temps := map[*Node]*ssa.Value{}
+ for _, a := range n.List.Slice() {
+ if a.Op != OAS {
+ s.Fatalf("non-assignment as a temp function argument %v", a.Op)
+ }
+ l, r := a.Left, a.Right
+ if l.Op != ONAME {
+ s.Fatalf("non-ONAME temp function argument %v", a.Op)
+ }
+ // Evaluate and store to "temporary".
+ // Walk ensures these temporaries are dead outside of n.
+ temps[l] = s.expr(r)
+ }
+ args := make([]*ssa.Value, n.Rlist.Len())
+ for i, n := range n.Rlist.Slice() {
+ // Store a value to an argument slot.
+ if x, ok := temps[n]; ok {
+ // This is a previously computed temporary.
+ args[i] = x
+ continue
+ }
+ // This is an explicit value; evaluate it.
+ args[i] = s.expr(n)
+ }
+ return args
+}
+
+// openDeferRecord adds code to evaluate and store the args for an open-code defer
+// call, and records info about the defer, so we can generate proper code on the
+// exit paths. n is the sub-node of the defer node that is the actual function
+// call. We will also record funcdata information on where the args are stored
+// (as well as the deferBits variable), and this will enable us to run the proper
+// defer calls during panics.
+func (s *state) openDeferRecord(n *Node) {
+ // Do any needed expression evaluation for the args (including the
+ // receiver, if any). This may be evaluating something like 'autotmp_3 =
+ // once.mutex'. Such a statement will create a mapping in s.vars[] from
+ // the autotmp name to the evaluated SSA arg value, but won't do any
+ // stores to the stack.
+ s.stmtList(n.List)
+
+ var args []*ssa.Value
+ var argNodes []*Node
+
+ opendefer := &openDeferInfo{
+ n: n,
+ }
+ fn := n.Left
+ if n.Op == OCALLFUNC {
+ // We must always store the function value in a stack slot for the
+ // runtime panic code to use. But in the defer exit code, we will
+ // call the function directly if it is a static function.
+ closureVal := s.expr(fn)
+ closure := s.openDeferSave(nil, fn.Type, closureVal)
+ opendefer.closureNode = closure.Aux.(*Node)
+ if !(fn.Op == ONAME && fn.Class() == PFUNC) {
+ opendefer.closure = closure
+ }
+ } else if n.Op == OCALLMETH {
+ if fn.Op != ODOTMETH {
+ Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
+ }
+ closureVal := s.getMethodClosure(fn)
+ // We must always store the function value in a stack slot for the
+ // runtime panic code to use. But in the defer exit code, we will
+ // call the method directly.
+ closure := s.openDeferSave(nil, fn.Type, closureVal)
+ opendefer.closureNode = closure.Aux.(*Node)
+ } else {
+ if fn.Op != ODOTINTER {
+ Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
+ }
+ closure, rcvr := s.getClosureAndRcvr(fn)
+ opendefer.closure = s.openDeferSave(nil, closure.Type, closure)
+ // Important to get the receiver type correct, so it is recognized
+ // as a pointer for GC purposes.
+ opendefer.rcvr = s.openDeferSave(nil, fn.Type.Recv().Type, rcvr)
+ opendefer.closureNode = opendefer.closure.Aux.(*Node)
+ opendefer.rcvrNode = opendefer.rcvr.Aux.(*Node)
+ }
+ for _, argn := range n.Rlist.Slice() {
+ var v *ssa.Value
+ if canSSAType(argn.Type) {
+ v = s.openDeferSave(nil, argn.Type, s.expr(argn))
+ } else {
+ v = s.openDeferSave(argn, argn.Type, nil)
+ }
+ args = append(args, v)
+ argNodes = append(argNodes, v.Aux.(*Node))
+ }
+ opendefer.argVals = args
+ opendefer.argNodes = argNodes
+ index := len(s.openDefers)
+ s.openDefers = append(s.openDefers, opendefer)
+
+ // Update deferBits only after evaluation and storage to stack of
+ // args/receiver/interface is successful.
+ bitvalue := s.constInt8(types.Types[TUINT8], 1<<uint(index))
+ newDeferBits := s.newValue2(ssa.OpOr8, types.Types[TUINT8], s.variable(&deferBitsVar, types.Types[TUINT8]), bitvalue)
+ s.vars[&deferBitsVar] = newDeferBits
+ s.store(types.Types[TUINT8], s.deferBitsAddr, newDeferBits)
+}
+
+// openDeferSave generates SSA nodes to store a value (with type t) for an
+// open-coded defer at an explicit autotmp location on the stack, so it can be
+// reloaded and used for the appropriate call on exit. If type t is SSAable, then
+// val must be non-nil (and n should be nil) and val is the value to be stored. If
+// type t is non-SSAable, then n must be non-nil (and val should be nil) and n is
+// evaluated (via s.addr() below) to get the value that is to be stored. The
+// function returns an SSA value representing a pointer to the autotmp location.
+func (s *state) openDeferSave(n *Node, t *types.Type, val *ssa.Value) *ssa.Value {
+ canSSA := canSSAType(t)
+ var pos src.XPos
+ if canSSA {
+ pos = val.Pos
+ } else {
+ pos = n.Pos
+ }
+ argTemp := tempAt(pos.WithNotStmt(), s.curfn, t)
+ argTemp.Name.SetOpenDeferSlot(true)
+ var addrArgTemp *ssa.Value
+ // Use OpVarLive to make sure stack slots for the args, etc. are not
+ // removed by dead-store elimination
+ if s.curBlock.ID != s.f.Entry.ID {
+ // Force the argtmp storing this defer function/receiver/arg to be
+ // declared in the entry block, so that it will be live for the
+ // defer exit code (which will actually access it only if the
+ // associated defer call has been activated).
+ s.defvars[s.f.Entry.ID][&memVar] = s.entryNewValue1A(ssa.OpVarDef, types.TypeMem, argTemp, s.defvars[s.f.Entry.ID][&memVar])
+ s.defvars[s.f.Entry.ID][&memVar] = s.entryNewValue1A(ssa.OpVarLive, types.TypeMem, argTemp, s.defvars[s.f.Entry.ID][&memVar])
+ addrArgTemp = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(argTemp.Type), argTemp, s.sp, s.defvars[s.f.Entry.ID][&memVar])
+ } else {
+ // Special case if we're still in the entry block. We can't use
+ // the above code, since s.defvars[s.f.Entry.ID] isn't defined
+ // until we end the entry block with s.endBlock().
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, argTemp, s.mem(), false)
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, argTemp, s.mem(), false)
+ addrArgTemp = s.newValue2Apos(ssa.OpLocalAddr, types.NewPtr(argTemp.Type), argTemp, s.sp, s.mem(), false)
+ }
+ if t.HasPointers() {
+ // Since we may use this argTemp during exit depending on the
+ // deferBits, we must define it unconditionally on entry.
+ // Therefore, we must make sure it is zeroed out in the entry
+ // block if it contains pointers, else GC may wrongly follow an
+ // uninitialized pointer value.
+ argTemp.Name.SetNeedzero(true)
+ }
+ if !canSSA {
+ a := s.addr(n)
+ s.move(t, addrArgTemp, a)
+ return addrArgTemp
+ }
+ // We are storing to the stack, hence we can avoid the full checks in
+ // storeType() (no write barrier) and do a simple store().
+ s.store(t, addrArgTemp, val)
+ return addrArgTemp
+}
+
+// openDeferExit generates SSA for processing all the open coded defers at exit.
+// The code involves loading deferBits, and checking each of the bits to see if
+// the corresponding defer statement was executed. For each bit that is turned
+// on, the associated defer call is made.
+func (s *state) openDeferExit() {
+ deferExit := s.f.NewBlock(ssa.BlockPlain)
+ s.endBlock().AddEdgeTo(deferExit)
+ s.startBlock(deferExit)
+ s.lastDeferExit = deferExit
+ s.lastDeferCount = len(s.openDefers)
+ zeroval := s.constInt8(types.Types[TUINT8], 0)
+ testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
+ // Test for and run defers in reverse order
+ for i := len(s.openDefers) - 1; i >= 0; i-- {
+ r := s.openDefers[i]
+ bCond := s.f.NewBlock(ssa.BlockPlain)
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+ deferBits := s.variable(&deferBitsVar, types.Types[TUINT8])
+ // Generate code to check if the bit associated with the current
+ // defer is set.
+ bitval := s.constInt8(types.Types[TUINT8], 1<<uint(i))
+ andval := s.newValue2(ssa.OpAnd8, types.Types[TUINT8], deferBits, bitval)
+ eqVal := s.newValue2(ssa.OpEq8, types.Types[TBOOL], andval, zeroval)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(eqVal)
+ b.AddEdgeTo(bEnd)
+ b.AddEdgeTo(bCond)
+ bCond.AddEdgeTo(bEnd)
+ s.startBlock(bCond)
+
+ // Clear this bit in deferBits and force store back to stack, so
+ // we will not try to re-run this defer call if this defer call panics.
+ nbitval := s.newValue1(ssa.OpCom8, types.Types[TUINT8], bitval)
+ maskedval := s.newValue2(ssa.OpAnd8, types.Types[TUINT8], deferBits, nbitval)
+ s.store(types.Types[TUINT8], s.deferBitsAddr, maskedval)
+ // Use this value for following tests, so we keep previous
+ // bits cleared.
+ s.vars[&deferBitsVar] = maskedval
+
+ // Generate code to call the function call of the defer, using the
+ // closure/receiver/args that were stored in argtmps at the point
+ // of the defer statement.
+ argStart := Ctxt.FixedFrameSize()
+ fn := r.n.Left
+ stksize := fn.Type.ArgWidth()
+ var ACArgs []ssa.Param
+ var ACResults []ssa.Param
+ var callArgs []*ssa.Value
+ if r.rcvr != nil {
+ // rcvr in case of OCALLINTER
+ v := s.load(r.rcvr.Type.Elem(), r.rcvr)
+ addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
+ if testLateExpansion {
+ callArgs = append(callArgs, v)
+ } else {
+ s.store(types.Types[TUINTPTR], addr, v)
+ }
+ }
+ for j, argAddrVal := range r.argVals {
+ f := getParam(r.n, j)
+ pt := types.NewPtr(f.Type)
+ ACArgs = append(ACArgs, ssa.Param{Type: f.Type, Offset: int32(argStart + f.Offset)})
+ if testLateExpansion {
+ var a *ssa.Value
+ if !canSSAType(f.Type) {
+ a = s.newValue2(ssa.OpDereference, f.Type, argAddrVal, s.mem())
+ } else {
+ a = s.load(f.Type, argAddrVal)
+ }
+ callArgs = append(callArgs, a)
+ } else {
+ addr := s.constOffPtrSP(pt, argStart+f.Offset)
+ if !canSSAType(f.Type) {
+ s.move(f.Type, addr, argAddrVal)
+ } else {
+ argVal := s.load(f.Type, argAddrVal)
+ s.storeType(f.Type, addr, argVal, 0, false)
+ }
+ }
+ }
+ var call *ssa.Value
+ if r.closure != nil {
+ v := s.load(r.closure.Type.Elem(), r.closure)
+ s.maybeNilCheckClosure(v, callDefer)
+ codeptr := s.rawLoad(types.Types[TUINTPTR], v)
+ aux := ssa.ClosureAuxCall(ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, aux, codeptr, v, s.mem())
+ }
+ } else {
+ aux := ssa.StaticAuxCall(fn.Sym.Linksym(), ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ // Do a static call if the original call was a static function or method
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
+ }
+ call.AuxInt = stksize
+ if testLateExpansion {
+ s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
+ } else {
+ s.vars[&memVar] = call
+ }
+ // Make sure that the stack slots with pointers are kept live
+ // through the call (which is a pre-emption point). Also, we will
+ // use the first call of the last defer exit to compute liveness
+ // for the deferreturn, so we want all stack slots to be live.
+ if r.closureNode != nil {
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.closureNode, s.mem(), false)
+ }
+ if r.rcvrNode != nil {
+ if r.rcvrNode.Type.HasPointers() {
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.rcvrNode, s.mem(), false)
+ }
+ }
+ for _, argNode := range r.argNodes {
+ if argNode.Type.HasPointers() {
+ s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, argNode, s.mem(), false)
+ }
+ }
+
+ s.endBlock()
+ s.startBlock(bEnd)
+ }
+}
+
+func (s *state) callResult(n *Node, k callKind) *ssa.Value {
+ return s.call(n, k, false)
+}
+
+func (s *state) callAddr(n *Node, k callKind) *ssa.Value {
+ return s.call(n, k, true)
+}
+
+// Calls the function n using the specified call type.
+// Returns the address of the return value (or nil if none).
+func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
+ s.prevCall = nil
+ var sym *types.Sym // target symbol (if static)
+ var closure *ssa.Value // ptr to closure to run (if dynamic)
+ var codeptr *ssa.Value // ptr to target code (if dynamic)
+ var rcvr *ssa.Value // receiver to set
+ fn := n.Left
+ var ACArgs []ssa.Param
+ var ACResults []ssa.Param
+ var callArgs []*ssa.Value
+ res := n.Left.Type.Results()
+ if k == callNormal {
+ nf := res.NumFields()
+ for i := 0; i < nf; i++ {
+ fp := res.Field(i)
+ ACResults = append(ACResults, ssa.Param{Type: fp.Type, Offset: int32(fp.Offset + Ctxt.FixedFrameSize())})
+ }
+ }
+
+ testLateExpansion := false
+
+ switch n.Op {
+ case OCALLFUNC:
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
+ if k == callNormal && fn.Op == ONAME && fn.Class() == PFUNC {
+ sym = fn.Sym
+ break
+ }
+ closure = s.expr(fn)
+ if k != callDefer && k != callDeferStack {
+ // Deferred nil function needs to panic when the function is invoked,
+ // not the point of defer statement.
+ s.maybeNilCheckClosure(closure, k)
+ }
+ case OCALLMETH:
+ if fn.Op != ODOTMETH {
+ s.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
+ }
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
+ if k == callNormal {
+ sym = fn.Sym
+ break
+ }
+ closure = s.getMethodClosure(fn)
+ // Note: receiver is already present in n.Rlist, so we don't
+ // want to set it here.
+ case OCALLINTER:
+ if fn.Op != ODOTINTER {
+ s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
+ }
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
+ var iclosure *ssa.Value
+ iclosure, rcvr = s.getClosureAndRcvr(fn)
+ if k == callNormal {
+ codeptr = s.load(types.Types[TUINTPTR], iclosure)
+ } else {
+ closure = iclosure
+ }
+ }
+ dowidth(fn.Type)
+ stksize := fn.Type.ArgWidth() // includes receiver, args, and results
+
+ // Run all assignments of temps.
+ // The temps are introduced to avoid overwriting argument
+ // slots when arguments themselves require function calls.
+ s.stmtList(n.List)
+
+ var call *ssa.Value
+ if k == callDeferStack {
+ testLateExpansion = ssa.LateCallExpansionEnabledWithin(s.f)
+ // Make a defer struct d on the stack.
+ t := deferstruct(stksize)
+ d := tempAt(n.Pos, s.curfn, t)
+
+ s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, d, s.mem())
+ addr := s.addr(d)
+
+ // Must match reflect.go:deferstruct and src/runtime/runtime2.go:_defer.
+ // 0: siz
+ s.store(types.Types[TUINT32],
+ s.newValue1I(ssa.OpOffPtr, types.Types[TUINT32].PtrTo(), t.FieldOff(0), addr),
+ s.constInt32(types.Types[TUINT32], int32(stksize)))
+ // 1: started, set in deferprocStack
+ // 2: heap, set in deferprocStack
+ // 3: openDefer
+ // 4: sp, set in deferprocStack
+ // 5: pc, set in deferprocStack
+ // 6: fn
+ s.store(closure.Type,
+ s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(6), addr),
+ closure)
+ // 7: panic, set in deferprocStack
+ // 8: link, set in deferprocStack
+ // 9: framepc
+ // 10: varp
+ // 11: fd
+
+ // Then, store all the arguments of the defer call.
+ ft := fn.Type
+ off := t.FieldOff(12)
+ args := n.Rlist.Slice()
+
+ // Set receiver (for interface calls). Always a pointer.
+ if rcvr != nil {
+ p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr)
+ s.store(types.Types[TUINTPTR], p, rcvr)
+ }
+ // Set receiver (for method calls).
+ if n.Op == OCALLMETH {
+ f := ft.Recv()
+ s.storeArgWithBase(args[0], f.Type, addr, off+f.Offset)
+ args = args[1:]
+ }
+ // Set other args.
+ for _, f := range ft.Params().Fields().Slice() {
+ s.storeArgWithBase(args[0], f.Type, addr, off+f.Offset)
+ args = args[1:]
+ }
+
+ // Call runtime.deferprocStack with pointer to _defer record.
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(Ctxt.FixedFrameSize())})
+ aux := ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, addr, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ arg0 := s.constOffPtrSP(types.Types[TUINTPTR], Ctxt.FixedFrameSize())
+ s.store(types.Types[TUINTPTR], arg0, addr)
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
+ if stksize < int64(Widthptr) {
+ // We need room for both the call to deferprocStack and the call to
+ // the deferred function.
+ // TODO Revisit this if/when we pass args in registers.
+ stksize = int64(Widthptr)
+ }
+ call.AuxInt = stksize
+ } else {
+ // Store arguments to stack, including defer/go arguments and receiver for method calls.
+ // These are written in SP-offset order.
+ argStart := Ctxt.FixedFrameSize()
+ // Defer/go args.
+ if k != callNormal {
+ // Write argsize and closure (args to newproc/deferproc).
+ argsize := s.constInt32(types.Types[TUINT32], int32(stksize))
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINT32], Offset: int32(argStart)})
+ if testLateExpansion {
+ callArgs = append(callArgs, argsize)
+ } else {
+ addr := s.constOffPtrSP(s.f.Config.Types.UInt32Ptr, argStart)
+ s.store(types.Types[TUINT32], addr, argsize)
+ }
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart) + int32(Widthptr)})
+ if testLateExpansion {
+ callArgs = append(callArgs, closure)
+ } else {
+ addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart+int64(Widthptr))
+ s.store(types.Types[TUINTPTR], addr, closure)
+ }
+ stksize += 2 * int64(Widthptr)
+ argStart += 2 * int64(Widthptr)
+ }
+
+ // Set receiver (for interface calls).
+ if rcvr != nil {
+ addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
+ ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
+ if testLateExpansion {
+ callArgs = append(callArgs, rcvr)
+ } else {
+ s.store(types.Types[TUINTPTR], addr, rcvr)
+ }
+ }
+
+ // Write args.
+ t := n.Left.Type
+ args := n.Rlist.Slice()
+ if n.Op == OCALLMETH {
+ f := t.Recv()
+ ACArg, arg := s.putArg(args[0], f.Type, argStart+f.Offset, testLateExpansion)
+ ACArgs = append(ACArgs, ACArg)
+ callArgs = append(callArgs, arg)
+ args = args[1:]
+ }
+ for i, n := range args {
+ f := t.Params().Field(i)
+ ACArg, arg := s.putArg(n, f.Type, argStart+f.Offset, testLateExpansion)
+ ACArgs = append(ACArgs, ACArg)
+ callArgs = append(callArgs, arg)
+ }
+
+ callArgs = append(callArgs, s.mem())
+
+ // call target
+ switch {
+ case k == callDefer:
+ aux := ssa.StaticAuxCall(deferproc, ACArgs, ACResults)
+ if testLateExpansion {
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
+ case k == callGo:
+ aux := ssa.StaticAuxCall(newproc, ACArgs, ACResults)
+ if testLateExpansion {
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
+ case closure != nil:
+ // rawLoad because loading the code pointer from a
+ // closure is always safe, but IsSanitizerSafeAddr
+ // can't always figure that out currently, and it's
+ // critical that we not clobber any arguments already
+ // stored onto the stack.
+ codeptr = s.rawLoad(types.Types[TUINTPTR], closure)
+ if testLateExpansion {
+ aux := ssa.ClosureAuxCall(ACArgs, ACResults)
+ call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, closure, s.mem())
+ }
+ case codeptr != nil:
+ if testLateExpansion {
+ aux := ssa.InterfaceAuxCall(ACArgs, ACResults)
+ call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue2A(ssa.OpInterCall, types.TypeMem, ssa.InterfaceAuxCall(ACArgs, ACResults), codeptr, s.mem())
+ }
+ case sym != nil:
+ if testLateExpansion {
+ aux := ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults)
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults), s.mem())
+ }
+ default:
+ s.Fatalf("bad call type %v %v", n.Op, n)
+ }
+ call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
+ }
+ if testLateExpansion {
+ s.prevCall = call
+ s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
+ } else {
+ s.vars[&memVar] = call
+ }
+ // Insert OVARLIVE nodes
+ s.stmtList(n.Nbody)
+
+ // Finish block for defers
+ if k == callDefer || k == callDeferStack {
+ 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)
+ }
+
+ if res.NumFields() == 0 || k != callNormal {
+ // call has no return value. Continue with the next statement.
+ return nil
+ }
+ fp := res.Field(0)
+ if returnResultAddr {
+ pt := types.NewPtr(fp.Type)
+ if testLateExpansion {
+ return s.newValue1I(ssa.OpSelectNAddr, pt, 0, call)
+ }
+ return s.constOffPtrSP(pt, fp.Offset+Ctxt.FixedFrameSize())
+ }
+
+ if testLateExpansion {
+ return s.newValue1I(ssa.OpSelectN, fp.Type, 0, call)
+ }
+ return s.load(n.Type, s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize()))
+}
+
+// maybeNilCheckClosure checks if a nil check of a closure is needed in some
+// architecture-dependent situations and, if so, emits the nil check.
+func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) {
+ if thearch.LinkArch.Family == sys.Wasm || objabi.GOOS == "aix" && k != callGo {
+ // On AIX, the closure needs to be verified as fn can be nil, except if it's a call go. This needs to be handled by the runtime to have the "go of nil func value" error.
+ // TODO(neelance): On other architectures this should be eliminated by the optimization steps
+ s.nilCheck(closure)
+ }
+}
+
+// getMethodClosure returns a value representing the closure for a method call
+func (s *state) getMethodClosure(fn *Node) *ssa.Value {
+ // 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 := newnamel(fn.Pos, fn.Sym)
+ n2.Name.Curfn = s.curfn
+ n2.SetClass(PFUNC)
+ // n2.Sym already existed, so it's already marked as a function.
+ n2.Pos = fn.Pos
+ n2.Type = types.Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it.
+ return s.expr(n2)
+}
+
+// getClosureAndRcvr returns values for the appropriate closure and receiver of an
+// interface call
+func (s *state) getClosureAndRcvr(fn *Node) (*ssa.Value, *ssa.Value) {
+ i := s.expr(fn.Left)
+ itab := s.newValue1(ssa.OpITab, types.Types[TUINTPTR], i)
+ s.nilCheck(itab)
+ itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab
+ closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
+ rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
+ return closure, rcvr
+}
+
+// etypesign returns the signed-ness of e, for integer/pointer etypes.
+// -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
+func etypesign(e types.EType) int8 {
+ switch e {
+ case TINT8, TINT16, TINT32, TINT64, TINT:
+ return -1
+ case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
+ return +1
+ }
+ return 0
+}
+
+// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
+// The value that the returned Value represents is guaranteed to be non-nil.
+func (s *state) addr(n *Node) *ssa.Value {
+ if n.Op != ONAME {
+ s.pushLine(n.Pos)
+ defer s.popLine()
+ }
+
+ t := types.NewPtr(n.Type)
+ switch n.Op {
+ case ONAME:
+ switch n.Class() {
+ case PEXTERN:
+ // global variable
+ v := s.entryNewValue1A(ssa.OpAddr, t, n.Sym.Linksym(), s.sb)
+ // TODO: Make OpAddr use AuxInt as well as Aux.
+ if n.Xoffset != 0 {
+ v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
+ }
+ return v
+ case PPARAM:
+ // parameter slot
+ v := s.decladdrs[n]
+ if v != nil {
+ return v
+ }
+ if n == nodfp {
+ // Special arg that points to the frame pointer (Used by ORECOVER).
+ return s.entryNewValue2A(ssa.OpLocalAddr, t, n, s.sp, s.startmem)
+ }
+ s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
+ return nil
+ case PAUTO:
+ return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), !n.IsAutoTmp())
+
+ case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
+ // ensure that we reuse symbols for out parameters so
+ // that cse works on their addresses
+ return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
+ default:
+ s.Fatalf("variable address class %v not implemented", n.Class())
+ return nil
+ }
+ case ORESULT:
+ // load return from callee
+ if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
+ return s.constOffPtrSP(t, n.Xoffset)
+ }
+ which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Xoffset)
+ if which == -1 {
+ // Do the old thing // TODO: Panic instead.
+ return s.constOffPtrSP(t, n.Xoffset)
+ }
+ x := s.newValue1I(ssa.OpSelectNAddr, t, which, s.prevCall)
+ return x
+
+ case OINDEX:
+ if n.Left.Type.IsSlice() {
+ a := s.expr(n.Left)
+ i := s.expr(n.Right)
+ len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], a)
+ i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
+ p := s.newValue1(ssa.OpSlicePtr, t, a)
+ return s.newValue2(ssa.OpPtrIndex, t, p, i)
+ } else { // array
+ a := s.addr(n.Left)
+ i := s.expr(n.Right)
+ len := s.constInt(types.Types[TINT], n.Left.Type.NumElem())
+ i = s.boundsCheck(i, len, ssa.BoundsIndex, n.Bounded())
+ return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.Left.Type.Elem()), a, i)
+ }
+ case ODEREF:
+ return s.exprPtr(n.Left, n.Bounded(), n.Pos)
+ case ODOT:
+ p := s.addr(n.Left)
+ return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
+ case ODOTPTR:
+ p := s.exprPtr(n.Left, n.Bounded(), n.Pos)
+ return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
+ case OCLOSUREVAR:
+ return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
+ s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr))
+ case OCONVNOP:
+ addr := s.addr(n.Left)
+ return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
+ case OCALLFUNC, OCALLINTER, OCALLMETH:
+ return s.callAddr(n, callNormal)
+ 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]
+ default:
+ s.Fatalf("unhandled addr %v", n.Op)
+ return nil
+ }
+}
+
+// canSSA reports whether n is SSA-able.
+// n must be an ONAME (or an ODOT sequence with an ONAME base).
+func (s *state) canSSA(n *Node) bool {
+ if Debug.N != 0 {
+ return false
+ }
+ for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) {
+ n = n.Left
+ }
+ if n.Op != ONAME {
+ return false
+ }
+ if n.Name.Addrtaken() {
+ return false
+ }
+ if n.isParamHeapCopy() {
+ return false
+ }
+ if n.Class() == PAUTOHEAP {
+ s.Fatalf("canSSA of PAUTOHEAP %v", n)
+ }
+ switch n.Class() {
+ case PEXTERN:
+ return false
+ case PPARAMOUT:
+ if s.hasdefer {
+ // TODO: handle this case? Named return values must be
+ // in memory so that the deferred function can see them.
+ // Maybe do: if !strings.HasPrefix(n.String(), "~") { return false }
+ // Or maybe not, see issue 18860. Even unnamed return values
+ // must be written back so if a defer recovers, the caller can see them.
+ return false
+ }
+ if s.cgoUnsafeArgs {
+ // Cgo effectively takes the address of all result args,
+ // but the compiler can't see that.
+ return false
+ }
+ }
+ if n.Class() == PPARAM && n.Sym != nil && n.Sym.Name == ".this" {
+ // wrappers generated by genwrapper need to update
+ // the .this pointer in place.
+ // TODO: treat as a PPARAMOUT?
+ return false
+ }
+ return canSSAType(n.Type)
+ // TODO: try to make more variables SSAable?
+}
+
+// canSSA reports whether variables of type t are SSA-able.
+func canSSAType(t *types.Type) bool {
+ dowidth(t)
+ if t.Width > int64(4*Widthptr) {
+ // 4*Widthptr is an arbitrary constant. We want it
+ // to be at least 3*Widthptr so slices can be registerized.
+ // Too big and we'll introduce too much register pressure.
+ return false
+ }
+ switch t.Etype {
+ case TARRAY:
+ // We can't do larger arrays because dynamic indexing is
+ // not supported on SSA variables.
+ // TODO: allow if all indexes are constant.
+ if t.NumElem() <= 1 {
+ return canSSAType(t.Elem())
+ }
+ return false
+ case TSTRUCT:
+ if t.NumFields() > ssa.MaxStruct {
+ return false
+ }
+ for _, t1 := range t.Fields().Slice() {
+ if !canSSAType(t1.Type) {
+ return false
+ }
+ }
+ return true
+ default:
+ return true
+ }
+}
+
+// exprPtr evaluates n to a pointer and nil-checks it.
+func (s *state) exprPtr(n *Node, bounded bool, lineno src.XPos) *ssa.Value {
+ p := s.expr(n)
+ if bounded || n.NonNil() {
+ if s.f.Frontend().Debug_checknil() && lineno.Line() > 1 {
+ s.f.Warnl(lineno, "removed nil check")
+ }
+ return p
+ }
+ s.nilCheck(p)
+ return p
+}
+
+// nilCheck generates nil pointer checking code.
+// 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 || s.curfn.Func.NilCheckDisabled() {
+ return
+ }
+ s.newValue2(ssa.OpNilCheck, types.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.
+// On input, len must be converted to full int width and be nonnegative.
+// Returns idx converted to full int width.
+// If bounded is true then caller guarantees the index is not out of bounds
+// (but boundsCheck will still extend the index to full int width).
+func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
+ idx = s.extendIndex(idx, len, kind, bounded)
+
+ if bounded || Debug.B != 0 {
+ // If bounded or bounds checking is flag-disabled, then no check necessary,
+ // just return the extended index.
+ //
+ // Here, bounded == true if the compiler generated the index itself,
+ // such as in the expansion of a slice initializer. These indexes are
+ // compiler-generated, not Go program variables, so they cannot be
+ // attacker-controlled, so we can omit Spectre masking as well.
+ //
+ // Note that we do not want to omit Spectre masking in code like:
+ //
+ // if 0 <= i && i < len(x) {
+ // use(x[i])
+ // }
+ //
+ // Lucky for us, bounded==false for that code.
+ // In that case (handled below), we emit a bound check (and Spectre mask)
+ // and then the prove pass will remove the bounds check.
+ // In theory the prove pass could potentially remove certain
+ // Spectre masks, but it's very delicate and probably better
+ // to be conservative and leave them all in.
+ return idx
+ }
+
+ bNext := s.f.NewBlock(ssa.BlockPlain)
+ bPanic := s.f.NewBlock(ssa.BlockExit)
+
+ if !idx.Type.IsSigned() {
+ switch kind {
+ case ssa.BoundsIndex:
+ kind = ssa.BoundsIndexU
+ case ssa.BoundsSliceAlen:
+ kind = ssa.BoundsSliceAlenU
+ case ssa.BoundsSliceAcap:
+ kind = ssa.BoundsSliceAcapU
+ case ssa.BoundsSliceB:
+ kind = ssa.BoundsSliceBU
+ case ssa.BoundsSlice3Alen:
+ kind = ssa.BoundsSlice3AlenU
+ case ssa.BoundsSlice3Acap:
+ kind = ssa.BoundsSlice3AcapU
+ case ssa.BoundsSlice3B:
+ kind = ssa.BoundsSlice3BU
+ case ssa.BoundsSlice3C:
+ kind = ssa.BoundsSlice3CU
+ }
+ }
+
+ var cmp *ssa.Value
+ if kind == ssa.BoundsIndex || kind == ssa.BoundsIndexU {
+ cmp = s.newValue2(ssa.OpIsInBounds, types.Types[TBOOL], idx, len)
+ } else {
+ cmp = s.newValue2(ssa.OpIsSliceInBounds, types.Types[TBOOL], idx, len)
+ }
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(cmp)
+ b.Likely = ssa.BranchLikely
+ b.AddEdgeTo(bNext)
+ b.AddEdgeTo(bPanic)
+
+ s.startBlock(bPanic)
+ if thearch.LinkArch.Family == sys.Wasm {
+ // TODO(khr): figure out how to do "register" based calling convention for bounds checks.
+ // Should be similar to gcWriteBarrier, but I can't make it work.
+ s.rtcall(BoundsCheckFunc[kind], false, nil, idx, len)
+ } else {
+ mem := s.newValue3I(ssa.OpPanicBounds, types.TypeMem, int64(kind), idx, len, s.mem())
+ s.endBlock().SetControl(mem)
+ }
+ s.startBlock(bNext)
+
+ // In Spectre index mode, apply an appropriate mask to avoid speculative out-of-bounds accesses.
+ if spectreIndex {
+ op := ssa.OpSpectreIndex
+ if kind != ssa.BoundsIndex && kind != ssa.BoundsIndexU {
+ op = ssa.OpSpectreSliceIndex
+ }
+ idx = s.newValue2(op, types.Types[TINT], idx, len)
+ }
+
+ return idx
+}
+
+// If cmp (a bool) is false, panic using the given function.
+func (s *state) check(cmp *ssa.Value, fn *obj.LSym) {
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(cmp)
+ b.Likely = ssa.BranchLikely
+ bNext := s.f.NewBlock(ssa.BlockPlain)
+ line := s.peekPos()
+ pos := Ctxt.PosTable.Pos(line)
+ fl := funcLine{f: fn, base: pos.Base(), line: pos.Line()}
+ bPanic := s.panics[fl]
+ if bPanic == nil {
+ bPanic = s.f.NewBlock(ssa.BlockPlain)
+ s.panics[fl] = bPanic
+ s.startBlock(bPanic)
+ // The panic call takes/returns memory to ensure that the right
+ // memory state is observed if the panic happens.
+ s.rtcall(fn, false, nil)
+ }
+ b.AddEdgeTo(bNext)
+ b.AddEdgeTo(bPanic)
+ 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.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.
+func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value {
+ s.prevCall = nil
+ // Write args to the stack
+ off := Ctxt.FixedFrameSize()
+ testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
+ var ACArgs []ssa.Param
+ var ACResults []ssa.Param
+ var callArgs []*ssa.Value
+
+ for _, arg := range args {
+ t := arg.Type
+ off = Rnd(off, t.Alignment())
+ size := t.Size()
+ ACArgs = append(ACArgs, ssa.Param{Type: t, Offset: int32(off)})
+ if testLateExpansion {
+ callArgs = append(callArgs, arg)
+ } else {
+ ptr := s.constOffPtrSP(t.PtrTo(), off)
+ s.store(t, ptr, arg)
+ }
+ off += size
+ }
+ off = Rnd(off, int64(Widthreg))
+
+ // Accumulate results types and offsets
+ offR := off
+ for _, t := range results {
+ offR = Rnd(offR, t.Alignment())
+ ACResults = append(ACResults, ssa.Param{Type: t, Offset: int32(offR)})
+ offR += t.Size()
+ }
+
+ // Issue call
+ var call *ssa.Value
+ aux := ssa.StaticAuxCall(fn, ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ s.vars[&memVar] = call
+ }
+
+ if !returns {
+ // Finish block
+ b := s.endBlock()
+ b.Kind = ssa.BlockExit
+ b.SetControl(call)
+ call.AuxInt = off - Ctxt.FixedFrameSize()
+ if len(results) > 0 {
+ s.Fatalf("panic call can't have results")
+ }
+ return nil
+ }
+
+ // Load results
+ res := make([]*ssa.Value, len(results))
+ if testLateExpansion {
+ for i, t := range results {
+ off = Rnd(off, t.Alignment())
+ if canSSAType(t) {
+ res[i] = s.newValue1I(ssa.OpSelectN, t, int64(i), call)
+ } else {
+ addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), int64(i), call)
+ res[i] = s.rawLoad(t, addr)
+ }
+ off += t.Size()
+ }
+ } else {
+ for i, t := range results {
+ off = Rnd(off, t.Alignment())
+ ptr := s.constOffPtrSP(types.NewPtr(t), off)
+ res[i] = s.load(t, ptr)
+ off += t.Size()
+ }
+ }
+ off = Rnd(off, int64(Widthptr))
+
+ // Remember how much callee stack space we needed.
+ call.AuxInt = off
+
+ return res
+}
+
+// do *left = right for type t.
+func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask, leftIsStmt bool) {
+ s.instrument(t, left, instrumentWrite)
+
+ if skip == 0 && (!t.HasPointers() || ssa.IsStackAddr(left)) {
+ // Known to not have write barrier. Store the whole type.
+ s.vars[&memVar] = s.newValue3Apos(ssa.OpStore, types.TypeMem, t, left, right, s.mem(), leftIsStmt)
+ return
+ }
+
+ // store scalar fields first, so write barrier stores for
+ // pointer fields can be grouped together, and scalar values
+ // don't need to be live across the write barrier call.
+ // TODO: if the writebarrier pass knows how to reorder stores,
+ // we can do a single store here as long as skip==0.
+ s.storeTypeScalars(t, left, right, skip)
+ if skip&skipPtr == 0 && t.HasPointers() {
+ s.storeTypePtrs(t, left, right)
+ }
+}
+
+// do *left = right for all scalar (non-pointer) parts of t.
+func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip skipMask) {
+ switch {
+ case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
+ s.store(t, left, right)
+ case t.IsPtrShaped():
+ if t.IsPtr() && t.Elem().NotInHeap() {
+ s.store(t, left, right) // see issue 42032
+ }
+ // otherwise, no scalar fields.
+ case t.IsString():
+ if skip&skipLen != 0 {
+ return
+ }
+ len := s.newValue1(ssa.OpStringLen, types.Types[TINT], right)
+ lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
+ s.store(types.Types[TINT], lenAddr, len)
+ case t.IsSlice():
+ if skip&skipLen == 0 {
+ len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], right)
+ lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left)
+ s.store(types.Types[TINT], lenAddr, len)
+ }
+ if skip&skipCap == 0 {
+ cap := s.newValue1(ssa.OpSliceCap, types.Types[TINT], right)
+ capAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, 2*s.config.PtrSize, left)
+ s.store(types.Types[TINT], capAddr, cap)
+ }
+ case t.IsInterface():
+ // itab field doesn't need a write barrier (even though it is a pointer).
+ itab := s.newValue1(ssa.OpITab, s.f.Config.Types.BytePtr, right)
+ s.store(types.Types[TUINTPTR], left, itab)
+ case t.IsStruct():
+ n := t.NumFields()
+ for i := 0; i < n; i++ {
+ ft := t.FieldType(i)
+ addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
+ val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
+ s.storeTypeScalars(ft, 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 %v", t)
+ }
+}
+
+// do *left = right for all pointer parts of t.
+func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
+ switch {
+ case t.IsPtrShaped():
+ if t.IsPtr() && t.Elem().NotInHeap() {
+ break // see issue 42032
+ }
+ s.store(t, left, right)
+ case t.IsString():
+ ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
+ s.store(s.f.Config.Types.BytePtr, left, ptr)
+ case t.IsSlice():
+ elType := types.NewPtr(t.Elem())
+ ptr := s.newValue1(ssa.OpSlicePtr, elType, right)
+ s.store(elType, left, ptr)
+ case t.IsInterface():
+ // itab field is treated as a scalar.
+ idata := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, right)
+ idataAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.BytePtrPtr, s.config.PtrSize, left)
+ s.store(s.f.Config.Types.BytePtr, idataAddr, idata)
+ case t.IsStruct():
+ n := t.NumFields()
+ for i := 0; i < n; i++ {
+ ft := t.FieldType(i)
+ if !ft.HasPointers() {
+ continue
+ }
+ addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
+ val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
+ s.storeTypePtrs(ft, 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 %v", t)
+ }
+}
+
+// putArg evaluates n for the purpose of passing it as an argument to a function and returns the corresponding Param for the call.
+// If forLateExpandedCall is true, it returns the argument value to pass to the call operation.
+// If forLateExpandedCall is false, then the value is stored at the specified stack offset, and the returned value is nil.
+func (s *state) putArg(n *Node, t *types.Type, off int64, forLateExpandedCall bool) (ssa.Param, *ssa.Value) {
+ var a *ssa.Value
+ if forLateExpandedCall {
+ if !canSSAType(t) {
+ a = s.newValue2(ssa.OpDereference, t, s.addr(n), s.mem())
+ } else {
+ a = s.expr(n)
+ }
+ } else {
+ s.storeArgWithBase(n, t, s.sp, off)
+ }
+ return ssa.Param{Type: t, Offset: int32(off)}, a
+}
+
+func (s *state) storeArgWithBase(n *Node, t *types.Type, base *ssa.Value, off int64) {
+ pt := types.NewPtr(t)
+ var addr *ssa.Value
+ if base == s.sp {
+ // Use special routine that avoids allocation on duplicate offsets.
+ addr = s.constOffPtrSP(pt, off)
+ } else {
+ addr = s.newValue1I(ssa.OpOffPtr, pt, off, base)
+ }
+
+ if !canSSAType(t) {
+ a := s.addr(n)
+ s.move(t, addr, a)
+ return
+ }
+
+ a := s.expr(n)
+ s.storeType(t, addr, a, 0, false)
+}
+
+// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
+// i,j,k may be nil, in which case they are set to their default value.
+// v may be a slice, string or pointer to an array.
+func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) {
+ t := v.Type
+ var ptr, len, cap *ssa.Value
+ switch {
+ case t.IsSlice():
+ ptr = s.newValue1(ssa.OpSlicePtr, types.NewPtr(t.Elem()), v)
+ len = s.newValue1(ssa.OpSliceLen, types.Types[TINT], v)
+ cap = s.newValue1(ssa.OpSliceCap, types.Types[TINT], v)
+ case t.IsString():
+ ptr = s.newValue1(ssa.OpStringPtr, types.NewPtr(types.Types[TUINT8]), v)
+ len = s.newValue1(ssa.OpStringLen, types.Types[TINT], v)
+ cap = len
+ case t.IsPtr():
+ if !t.Elem().IsArray() {
+ s.Fatalf("bad ptr to array in slice %v\n", t)
+ }
+ s.nilCheck(v)
+ ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), v)
+ len = s.constInt(types.Types[TINT], t.Elem().NumElem())
+ cap = len
+ default:
+ s.Fatalf("bad type in slice %v\n", t)
+ }
+
+ // Set default values
+ if i == nil {
+ i = s.constInt(types.Types[TINT], 0)
+ }
+ if j == nil {
+ j = len
+ }
+ three := true
+ if k == nil {
+ three = false
+ k = cap
+ }
+
+ // Panic if slice indices are not in bounds.
+ // Make sure we check these in reverse order so that we're always
+ // comparing against a value known to be nonnegative. See issue 28797.
+ if three {
+ if k != cap {
+ kind := ssa.BoundsSlice3Alen
+ if t.IsSlice() {
+ kind = ssa.BoundsSlice3Acap
+ }
+ k = s.boundsCheck(k, cap, kind, bounded)
+ }
+ if j != k {
+ j = s.boundsCheck(j, k, ssa.BoundsSlice3B, bounded)
+ }
+ i = s.boundsCheck(i, j, ssa.BoundsSlice3C, bounded)
+ } else {
+ if j != k {
+ kind := ssa.BoundsSliceAlen
+ if t.IsSlice() {
+ kind = ssa.BoundsSliceAcap
+ }
+ j = s.boundsCheck(j, k, kind, bounded)
+ }
+ i = s.boundsCheck(i, j, ssa.BoundsSliceB, bounded)
+ }
+
+ // Word-sized integer operations.
+ subOp := s.ssaOp(OSUB, types.Types[TINT])
+ mulOp := s.ssaOp(OMUL, types.Types[TINT])
+ andOp := s.ssaOp(OAND, types.Types[TINT])
+
+ // Calculate the length (rlen) and capacity (rcap) of the new slice.
+ // For strings the capacity of the result is unimportant. However,
+ // we use rcap to test if we've generated a zero-length slice.
+ // Use length of strings for that.
+ rlen := s.newValue2(subOp, types.Types[TINT], j, i)
+ rcap := rlen
+ if j != k && !t.IsString() {
+ rcap = s.newValue2(subOp, types.Types[TINT], k, i)
+ }
+
+ if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 {
+ // No pointer arithmetic necessary.
+ return ptr, rlen, rcap
+ }
+
+ // Calculate the base pointer (rptr) for the new slice.
+ //
+ // Generate the following code assuming that indexes are in bounds.
+ // The masking is to make sure that we don't generate a slice
+ // that points to the next object in memory. We cannot just set
+ // the pointer to nil because then we would create a nil slice or
+ // string.
+ //
+ // rcap = k - i
+ // rlen = j - i
+ // rptr = ptr + (mask(rcap) & (i * stride))
+ //
+ // Where mask(x) is 0 if x==0 and -1 if x>0 and stride is the width
+ // of the element type.
+ stride := s.constInt(types.Types[TINT], ptr.Type.Elem().Width)
+
+ // The delta is the number of bytes to offset ptr by.
+ delta := s.newValue2(mulOp, types.Types[TINT], i, stride)
+
+ // If we're slicing to the point where the capacity is zero,
+ // zero out the delta.
+ mask := s.newValue1(ssa.OpSlicemask, types.Types[TINT], rcap)
+ delta = s.newValue2(andOp, types.Types[TINT], delta, mask)
+
+ // Compute rptr = ptr + delta.
+ rptr := s.newValue2(ssa.OpAddPtr, ptr.Type, ptr, delta)
+
+ return rptr, rlen, rcap
+}
+
+type u642fcvtTab struct {
+ leq, cvt2F, and, rsh, or, add ssa.Op
+ one func(*state, *types.Type, int64) *ssa.Value
+}
+
+var u64_f64 = u642fcvtTab{
+ leq: ssa.OpLeq64,
+ cvt2F: ssa.OpCvt64to64F,
+ and: ssa.OpAnd64,
+ rsh: ssa.OpRsh64Ux64,
+ or: ssa.OpOr64,
+ add: ssa.OpAdd64F,
+ one: (*state).constInt64,
+}
+
+var u64_f32 = u642fcvtTab{
+ leq: ssa.OpLeq64,
+ cvt2F: ssa.OpCvt64to32F,
+ and: ssa.OpAnd64,
+ rsh: ssa.OpRsh64Ux64,
+ or: ssa.OpOr64,
+ add: ssa.OpAdd32F,
+ one: (*state).constInt64,
+}
+
+func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ return s.uint64Tofloat(&u64_f64, n, x, ft, tt)
+}
+
+func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ return s.uint64Tofloat(&u64_f32, n, x, ft, tt)
+}
+
+func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ // if x >= 0 {
+ // result = (floatY) x
+ // } else {
+ // y = uintX(x) ; y = x & 1
+ // z = uintX(x) ; z = z >> 1
+ // z = z >> 1
+ // z = z | y
+ // result = floatY(z)
+ // result = result + result
+ // }
+ //
+ // Code borrowed from old code generator.
+ // What's going on: large 64-bit "unsigned" looks like
+ // negative number to hardware's integer-to-float
+ // conversion. However, because the mantissa is only
+ // 63 bits, we don't need the LSB, so instead we do an
+ // unsigned right shift (divide by two), convert, and
+ // double. However, before we do that, we need to be
+ // sure that we do not lose a "1" if that made the
+ // difference in the resulting rounding. Therefore, we
+ // preserve it, and OR (not ADD) it back in. The case
+ // that matters is when the eleven discarded bits are
+ // equal to 10000000001; that rounds up, and the 1 cannot
+ // be lost else it would round down if the LSB of the
+ // candidate mantissa is 0.
+ cmp := s.newValue2(cvttab.leq, types.Types[TBOOL], s.zeroVal(ft), x)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(cmp)
+ b.Likely = ssa.BranchLikely
+
+ bThen := s.f.NewBlock(ssa.BlockPlain)
+ bElse := s.f.NewBlock(ssa.BlockPlain)
+ bAfter := s.f.NewBlock(ssa.BlockPlain)
+
+ b.AddEdgeTo(bThen)
+ s.startBlock(bThen)
+ a0 := s.newValue1(cvttab.cvt2F, tt, x)
+ s.vars[n] = a0
+ s.endBlock()
+ bThen.AddEdgeTo(bAfter)
+
+ b.AddEdgeTo(bElse)
+ s.startBlock(bElse)
+ one := cvttab.one(s, ft, 1)
+ y := s.newValue2(cvttab.and, ft, x, one)
+ z := s.newValue2(cvttab.rsh, ft, x, one)
+ z = s.newValue2(cvttab.or, ft, z, y)
+ a := s.newValue1(cvttab.cvt2F, tt, z)
+ a1 := s.newValue2(cvttab.add, tt, a, a)
+ s.vars[n] = a1
+ s.endBlock()
+ bElse.AddEdgeTo(bAfter)
+
+ s.startBlock(bAfter)
+ return s.variable(n, n.Type)
+}
+
+type u322fcvtTab struct {
+ cvtI2F, cvtF2F ssa.Op
+}
+
+var u32_f64 = u322fcvtTab{
+ cvtI2F: ssa.OpCvt32to64F,
+ cvtF2F: ssa.OpCopy,
+}
+
+var u32_f32 = u322fcvtTab{
+ cvtI2F: ssa.OpCvt32to32F,
+ cvtF2F: ssa.OpCvt64Fto32F,
+}
+
+func (s *state) uint32Tofloat64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ return s.uint32Tofloat(&u32_f64, n, x, ft, tt)
+}
+
+func (s *state) uint32Tofloat32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ return s.uint32Tofloat(&u32_f32, n, x, ft, tt)
+}
+
+func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ // if x >= 0 {
+ // result = floatY(x)
+ // } else {
+ // result = floatY(float64(x) + (1<<32))
+ // }
+ cmp := s.newValue2(ssa.OpLeq32, types.Types[TBOOL], s.zeroVal(ft), x)
+ 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.Types[TFLOAT64], x)
+ twoToThe32 := s.constFloat64(types.Types[TFLOAT64], float64(1<<32))
+ a2 := s.newValue2(ssa.OpAdd64F, types.Types[TFLOAT64], a1, twoToThe32)
+ a3 := s.newValue1(cvttab.cvtF2F, tt, a2)
+
+ s.vars[n] = a3
+ s.endBlock()
+ bElse.AddEdgeTo(bAfter)
+
+ s.startBlock(bAfter)
+ return s.variable(n, n.Type)
+}
+
+// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
+func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
+ if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
+ s.Fatalf("node must be a map or a channel")
+ }
+ // if n == nil {
+ // return 0
+ // } else {
+ // // len
+ // return *((*int)n)
+ // // cap
+ // return *(((*int)n)+1)
+ // }
+ lenType := n.Type
+ nilValue := s.constNil(types.Types[TUINTPTR])
+ cmp := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], x, nilValue)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(cmp)
+ b.Likely = ssa.BranchUnlikely
+
+ bThen := s.f.NewBlock(ssa.BlockPlain)
+ bElse := s.f.NewBlock(ssa.BlockPlain)
+ bAfter := s.f.NewBlock(ssa.BlockPlain)
+
+ // length/capacity of a nil map/chan is zero
+ b.AddEdgeTo(bThen)
+ s.startBlock(bThen)
+ s.vars[n] = s.zeroVal(lenType)
+ s.endBlock()
+ bThen.AddEdgeTo(bAfter)
+
+ b.AddEdgeTo(bElse)
+ s.startBlock(bElse)
+ switch n.Op {
+ case OLEN:
+ // length is stored in the first word for map/chan
+ s.vars[n] = s.load(lenType, x)
+ case OCAP:
+ // capacity is stored in the second word for chan
+ sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
+ s.vars[n] = s.load(lenType, sw)
+ default:
+ s.Fatalf("op must be OLEN or OCAP")
+ }
+ s.endBlock()
+ bElse.AddEdgeTo(bAfter)
+
+ s.startBlock(bAfter)
+ return s.variable(n, lenType)
+}
+
+type f2uCvtTab struct {
+ ltf, cvt2U, subf, or ssa.Op
+ floatValue func(*state, *types.Type, float64) *ssa.Value
+ intValue func(*state, *types.Type, int64) *ssa.Value
+ cutoff uint64
+}
+
+var f32_u64 = f2uCvtTab{
+ ltf: ssa.OpLess32F,
+ cvt2U: ssa.OpCvt32Fto64,
+ subf: ssa.OpSub32F,
+ or: ssa.OpOr64,
+ floatValue: (*state).constFloat32,
+ intValue: (*state).constInt64,
+ cutoff: 1 << 63,
+}
+
+var f64_u64 = f2uCvtTab{
+ ltf: ssa.OpLess64F,
+ cvt2U: ssa.OpCvt64Fto64,
+ subf: ssa.OpSub64F,
+ or: ssa.OpOr64,
+ floatValue: (*state).constFloat64,
+ intValue: (*state).constInt64,
+ cutoff: 1 << 63,
+}
+
+var f32_u32 = f2uCvtTab{
+ ltf: ssa.OpLess32F,
+ cvt2U: ssa.OpCvt32Fto32,
+ subf: ssa.OpSub32F,
+ or: ssa.OpOr32,
+ floatValue: (*state).constFloat32,
+ intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
+ cutoff: 1 << 31,
+}
+
+var f64_u32 = f2uCvtTab{
+ ltf: ssa.OpLess64F,
+ cvt2U: ssa.OpCvt64Fto32,
+ subf: ssa.OpSub64F,
+ or: ssa.OpOr32,
+ floatValue: (*state).constFloat64,
+ intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) },
+ cutoff: 1 << 31,
+}
+
+func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ return s.floatToUint(&f32_u64, n, x, ft, tt)
+}
+func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ return s.floatToUint(&f64_u64, n, x, ft, tt)
+}
+
+func (s *state) float32ToUint32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ return s.floatToUint(&f32_u32, n, x, ft, tt)
+}
+
+func (s *state) float64ToUint32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ return s.floatToUint(&f64_u32, n, x, ft, tt)
+}
+
+func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value {
+ // cutoff:=1<<(intY_Size-1)
+ // if x < floatX(cutoff) {
+ // result = uintY(x)
+ // } else {
+ // y = x - floatX(cutoff)
+ // z = uintY(y)
+ // result = z | -(cutoff)
+ // }
+ cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff))
+ cmp := s.newValue2(cvttab.ltf, types.Types[TBOOL], x, cutoff)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(cmp)
+ b.Likely = ssa.BranchLikely
+
+ bThen := s.f.NewBlock(ssa.BlockPlain)
+ bElse := s.f.NewBlock(ssa.BlockPlain)
+ bAfter := s.f.NewBlock(ssa.BlockPlain)
+
+ b.AddEdgeTo(bThen)
+ s.startBlock(bThen)
+ a0 := s.newValue1(cvttab.cvt2U, tt, x)
+ s.vars[n] = a0
+ s.endBlock()
+ bThen.AddEdgeTo(bAfter)
+
+ b.AddEdgeTo(bElse)
+ s.startBlock(bElse)
+ y := s.newValue2(cvttab.subf, ft, x, cutoff)
+ y = s.newValue1(cvttab.cvt2U, tt, y)
+ 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)
+
+ s.startBlock(bAfter)
+ return s.variable(n, n.Type)
+}
+
+// dottype generates SSA for a type assertion node.
+// commaok indicates whether to panic or return a bool.
+// If commaok is false, resok will be nil.
+func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
+ iface := s.expr(n.Left) // input interface
+ target := s.expr(n.Right) // target type
+ byteptr := s.f.Config.Types.BytePtr
+
+ if n.Type.IsInterface() {
+ if n.Type.IsEmptyInterface() {
+ // Converting to an empty interface.
+ // Input could be an empty or nonempty interface.
+ if Debug_typeassert > 0 {
+ Warnl(n.Pos, "type assertion inlined")
+ }
+
+ // Get itab/type field from input.
+ itab := s.newValue1(ssa.OpITab, byteptr, iface)
+ // Conversion succeeds iff that field is not nil.
+ cond := s.newValue2(ssa.OpNeqPtr, types.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.load(byteptr, off)
+ idata := s.newValue1(ssa.OpIData, byteptr, 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.load(byteptr, off)
+ 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, byteptr, 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.Pos, "type assertion not inlined")
+ }
+ if n.Left.Type.IsEmptyInterface() {
+ if commaok {
+ call := s.rtcall(assertE2I2, true, []*types.Type{n.Type, types.Types[TBOOL]}, target, iface)
+ return call[0], call[1]
+ }
+ return s.rtcall(assertE2I, true, []*types.Type{n.Type}, target, iface)[0], nil
+ }
+ if commaok {
+ call := s.rtcall(assertI2I2, true, []*types.Type{n.Type, types.Types[TBOOL]}, target, iface)
+ return call[0], call[1]
+ }
+ return s.rtcall(assertI2I, true, []*types.Type{n.Type}, target, iface)[0], nil
+ }
+
+ if Debug_typeassert > 0 {
+ Warnl(n.Pos, "type assertion inlined")
+ }
+
+ // Converting to a concrete type.
+ direct := isdirectiface(n.Type)
+ itab := s.newValue1(ssa.OpITab, byteptr, iface) // type word of interface
+ if Debug_typeassert > 0 {
+ Warnl(n.Pos, "type assertion inlined")
+ }
+ var targetITab *ssa.Value
+ if n.Left.Type.IsEmptyInterface() {
+ // Looking for pointer to target type.
+ targetITab = target
+ } else {
+ // Looking for pointer to itab for target type and source interface.
+ targetITab = s.expr(n.List.First())
+ }
+
+ var tmp *Node // temporary for use with large types
+ 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 = tempAt(n.Pos, s.curfn, n.Type)
+ s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem())
+ addr = s.addr(tmp)
+ }
+
+ cond := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], itab, targetITab)
+ 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 panicdottype
+ s.startBlock(bFail)
+ taddr := s.expr(n.Right.Right)
+ if n.Left.Type.IsEmptyInterface() {
+ s.rtcall(panicdottypeE, false, nil, itab, target, taddr)
+ } else {
+ s.rtcall(panicdottypeI, false, nil, itab, target, taddr)
+ }
+
+ // on success, return data from interface
+ s.startBlock(bOk)
+ if direct {
+ return s.newValue1(ssa.OpIData, n.Type, iface), nil
+ }
+ p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface)
+ return s.load(n.Type, p), 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, Sym: &types.Sym{Name: "val"}}
+
+ // type assertion succeeded
+ s.startBlock(bOk)
+ if tmp == nil {
+ if direct {
+ s.vars[valVar] = s.newValue1(ssa.OpIData, n.Type, iface)
+ } else {
+ p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface)
+ s.vars[valVar] = s.load(n.Type, p)
+ }
+ } else {
+ p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface)
+ s.move(n.Type, addr, p)
+ }
+ s.vars[&okVar] = s.constBool(true)
+ s.endBlock()
+ bOk.AddEdgeTo(bEnd)
+
+ // type assertion failed
+ s.startBlock(bFail)
+ if tmp == nil {
+ s.vars[valVar] = s.zeroVal(n.Type)
+ } else {
+ s.zero(n.Type, addr)
+ }
+ s.vars[&okVar] = s.constBool(false)
+ s.endBlock()
+ bFail.AddEdgeTo(bEnd)
+
+ // merge point
+ s.startBlock(bEnd)
+ if tmp == nil {
+ res = s.variable(valVar, n.Type)
+ delete(s.vars, valVar)
+ } else {
+ res = s.load(n.Type, addr)
+ s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, types.TypeMem, tmp, s.mem())
+ }
+ resok = s.variable(&okVar, types.Types[TBOOL])
+ delete(s.vars, &okVar)
+ return res, resok
+}
+
+// variable returns the value of a variable at the current location.
+func (s *state) variable(name *Node, t *types.Type) *ssa.Value {
+ v := s.vars[name]
+ if v != nil {
+ return v
+ }
+ v = s.fwdVars[name]
+ if v != nil {
+ return v
+ }
+
+ 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)
+ }
+ // 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, types.TypeMem)
+}
+
+func (s *state) addNamedValue(n *Node, v *ssa.Value) {
+ if n.Class() == Pxxx {
+ // Don't track our dummy nodes (&memVar etc.).
+ return
+ }
+ if n.IsAutoTmp() {
+ // Don't track temporary variables.
+ return
+ }
+ if n.Class() == PPARAMOUT {
+ // Don't track named output values. This prevents return values
+ // from being assigned too early. See #14591 and #14762. TODO: allow this.
+ return
+ }
+ if n.Class() == PAUTO && n.Xoffset != 0 {
+ s.Fatalf("AUTO var with offset %v %d", n, n.Xoffset)
+ }
+ loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
+ values, ok := s.f.NamedValues[loc]
+ if !ok {
+ s.f.Names = append(s.f.Names, loc)
+ }
+ s.f.NamedValues[loc] = append(values, v)
+}
+
+// Generate a disconnected call to a runtime routine and a return.
+func gencallret(pp *Progs, sym *obj.LSym) *obj.Prog {
+ p := pp.Prog(obj.ACALL)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = sym
+ p = pp.Prog(obj.ARET)
+ return p
+}
+
+// Branch is an unresolved branch.
+type Branch struct {
+ P *obj.Prog // branch instruction
+ B *ssa.Block // target
+}
+
+// SSAGenState contains state needed during Prog generation.
+type SSAGenState struct {
+ pp *Progs
+
+ // Branches remembers all the branch instructions we've seen
+ // and where they would like to go.
+ Branches []Branch
+
+ // bstart remembers where each block starts (indexed by block ID)
+ bstart []*obj.Prog
+
+ // Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include PPC and Sparc V8.
+ ScratchFpMem *Node
+
+ maxarg int64 // largest frame size for arguments to calls made by the function
+
+ // Map from GC safe points to liveness index, generated by
+ // liveness analysis.
+ livenessMap LivenessMap
+
+ // lineRunStart records the beginning of the current run of instructions
+ // within a single block sharing the same line number
+ // Used to move statement marks to the beginning of such runs.
+ lineRunStart *obj.Prog
+
+ // wasm: The number of values on the WebAssembly stack. This is only used as a safeguard.
+ OnWasmStackSkipped int
+}
+
+// Prog appends a new Prog.
+func (s *SSAGenState) Prog(as obj.As) *obj.Prog {
+ p := s.pp.Prog(as)
+ if ssa.LosesStmtMark(as) {
+ return p
+ }
+ // Float a statement start to the beginning of any same-line run.
+ // lineRunStart is reset at block boundaries, which appears to work well.
+ if s.lineRunStart == nil || s.lineRunStart.Pos.Line() != p.Pos.Line() {
+ s.lineRunStart = p
+ } else if p.Pos.IsStmt() == src.PosIsStmt {
+ s.lineRunStart.Pos = s.lineRunStart.Pos.WithIsStmt()
+ p.Pos = p.Pos.WithNotStmt()
+ }
+ return p
+}
+
+// Pc returns the current Prog.
+func (s *SSAGenState) Pc() *obj.Prog {
+ return s.pp.next
+}
+
+// SetPos sets the current source position.
+func (s *SSAGenState) SetPos(pos src.XPos) {
+ s.pp.pos = pos
+}
+
+// Br emits a single branch instruction and returns the instruction.
+// Not all architectures need the returned instruction, but otherwise
+// the boilerplate is common to all.
+func (s *SSAGenState) Br(op obj.As, target *ssa.Block) *obj.Prog {
+ p := s.Prog(op)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, Branch{P: p, B: target})
+ return p
+}
+
+// DebugFriendlySetPosFrom adjusts Pos.IsStmt subject to heuristics
+// that reduce "jumpy" line number churn when debugging.
+// Spill/fill/copy instructions from the register allocator,
+// phi functions, and instructions with a no-pos position
+// are examples of instructions that can cause churn.
+func (s *SSAGenState) DebugFriendlySetPosFrom(v *ssa.Value) {
+ switch v.Op {
+ case ssa.OpPhi, ssa.OpCopy, ssa.OpLoadReg, ssa.OpStoreReg:
+ // These are not statements
+ s.SetPos(v.Pos.WithNotStmt())
+ default:
+ p := v.Pos
+ if p != src.NoXPos {
+ // If the position is defined, update the position.
+ // Also convert default IsStmt to NotStmt; only
+ // explicit statement boundaries should appear
+ // in the generated code.
+ if p.IsStmt() != src.PosIsStmt {
+ p = p.WithNotStmt()
+ // Calls use the pos attached to v, but copy the statement mark from SSAGenState
+ }
+ s.SetPos(p)
+ } else {
+ s.SetPos(s.pp.pos.WithNotStmt())
+ }
+ }
+}
+
+// byXoffset implements sort.Interface for []*Node using Xoffset as the ordering.
+type byXoffset []*Node
+
+func (s byXoffset) Len() int { return len(s) }
+func (s byXoffset) Less(i, j int) bool { return s[i].Xoffset < s[j].Xoffset }
+func (s byXoffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func emitStackObjects(e *ssafn, pp *Progs) {
+ var vars []*Node
+ for _, n := range e.curfn.Func.Dcl {
+ if livenessShouldTrack(n) && n.Name.Addrtaken() {
+ vars = append(vars, n)
+ }
+ }
+ if len(vars) == 0 {
+ return
+ }
+
+ // Sort variables from lowest to highest address.
+ sort.Sort(byXoffset(vars))
+
+ // Populate the stack object data.
+ // Format must match runtime/stack.go:stackObjectRecord.
+ x := e.curfn.Func.lsym.Func().StackObjects
+ off := 0
+ off = duintptr(x, off, uint64(len(vars)))
+ for _, v := range vars {
+ // Note: arguments and return values have non-negative Xoffset,
+ // in which case the offset is relative to argp.
+ // Locals have a negative Xoffset, in which case the offset is relative to varp.
+ off = duintptr(x, off, uint64(v.Xoffset))
+ if !typesym(v.Type).Siggen() {
+ e.Fatalf(v.Pos, "stack object's type symbol not generated for type %s", v.Type)
+ }
+ off = dsymptr(x, off, dtypesym(v.Type), 0)
+ }
+
+ // Emit a funcdata pointing at the stack object data.
+ p := pp.Prog(obj.AFUNCDATA)
+ Addrconst(&p.From, objabi.FUNCDATA_StackObjects)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = x
+
+ if debuglive != 0 {
+ for _, v := range vars {
+ Warnl(v.Pos, "stack object %v %s", v, v.Type.String())
+ }
+ }
+}
+
+// genssa appends entries to pp for each instruction in f.
+func genssa(f *ssa.Func, pp *Progs) {
+ var s SSAGenState
+
+ e := f.Frontend().(*ssafn)
+
+ s.livenessMap = liveness(e, f, pp)
+ emitStackObjects(e, pp)
+
+ openDeferInfo := e.curfn.Func.lsym.Func().OpenCodedDeferInfo
+ if openDeferInfo != nil {
+ // This function uses open-coded defers -- write out the funcdata
+ // info that we computed at the end of genssa.
+ p := pp.Prog(obj.AFUNCDATA)
+ Addrconst(&p.From, objabi.FUNCDATA_OpenCodedDeferInfo)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = openDeferInfo
+ }
+
+ // Remember where each block starts.
+ s.bstart = make([]*obj.Prog, f.NumBlocks())
+ s.pp = pp
+ var progToValue map[*obj.Prog]*ssa.Value
+ var progToBlock map[*obj.Prog]*ssa.Block
+ var valueToProgAfter []*obj.Prog // The first Prog following computation of a value v; v is visible at this point.
+ if f.PrintOrHtmlSSA {
+ progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
+ progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
+ f.Logf("genssa %s\n", f.Name)
+ progToBlock[s.pp.next] = f.Blocks[0]
+ }
+
+ s.ScratchFpMem = e.scratchFpMem
+
+ if Ctxt.Flag_locationlists {
+ if cap(f.Cache.ValueToProgAfter) < f.NumValues() {
+ f.Cache.ValueToProgAfter = make([]*obj.Prog, f.NumValues())
+ }
+ valueToProgAfter = f.Cache.ValueToProgAfter[:f.NumValues()]
+ for i := range valueToProgAfter {
+ valueToProgAfter[i] = nil
+ }
+ }
+
+ // If the very first instruction is not tagged as a statement,
+ // debuggers may attribute it to previous function in program.
+ firstPos := src.NoXPos
+ for _, v := range f.Entry.Values {
+ if v.Pos.IsStmt() == src.PosIsStmt {
+ firstPos = v.Pos
+ v.Pos = firstPos.WithDefaultStmt()
+ break
+ }
+ }
+
+ // inlMarks has an entry for each Prog that implements an inline mark.
+ // It maps from that Prog to the global inlining id of the inlined body
+ // which should unwind to this Prog's location.
+ var inlMarks map[*obj.Prog]int32
+ var inlMarkList []*obj.Prog
+
+ // inlMarksByPos maps from a (column 1) source position to the set of
+ // Progs that are in the set above and have that source position.
+ var inlMarksByPos map[src.XPos][]*obj.Prog
+
+ // Emit basic blocks
+ for i, b := range f.Blocks {
+ s.bstart[b.ID] = s.pp.next
+ s.lineRunStart = nil
+
+ // Attach a "default" liveness info. Normally this will be
+ // overwritten in the Values loop below for each Value. But
+ // for an empty block this will be used for its control
+ // instruction. We won't use the actual liveness map on a
+ // control instruction. Just mark it something that is
+ // preemptible, unless this function is "all unsafe".
+ s.pp.nextLive = LivenessIndex{-1, allUnsafe(f)}
+
+ // Emit values in block
+ thearch.SSAMarkMoves(&s, b)
+ for _, v := range b.Values {
+ x := s.pp.next
+ s.DebugFriendlySetPosFrom(v)
+
+ switch v.Op {
+ case ssa.OpInitMem:
+ // memory arg needs no code
+ case ssa.OpArg:
+ // input args need no code
+ case ssa.OpSP, ssa.OpSB:
+ // nothing to do
+ case ssa.OpSelect0, ssa.OpSelect1:
+ // nothing to do
+ case ssa.OpGetG:
+ // nothing to do when there's a g register,
+ // and checkLower complains if there's not
+ case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive, ssa.OpVarKill:
+ // nothing to do; already used by liveness
+ case ssa.OpPhi:
+ CheckLoweredPhi(v)
+ case ssa.OpConvert:
+ // nothing to do; no-op conversion for liveness
+ if v.Args[0].Reg() != v.Reg() {
+ v.Fatalf("OpConvert should be a no-op: %s; %s", v.Args[0].LongString(), v.LongString())
+ }
+ case ssa.OpInlMark:
+ p := thearch.Ginsnop(s.pp)
+ if inlMarks == nil {
+ inlMarks = map[*obj.Prog]int32{}
+ inlMarksByPos = map[src.XPos][]*obj.Prog{}
+ }
+ inlMarks[p] = v.AuxInt32()
+ inlMarkList = append(inlMarkList, p)
+ pos := v.Pos.AtColumn1()
+ inlMarksByPos[pos] = append(inlMarksByPos[pos], p)
+
+ default:
+ // Attach this safe point to the next
+ // instruction.
+ s.pp.nextLive = s.livenessMap.Get(v)
+
+ // Special case for first line in function; move it to the start.
+ if firstPos != src.NoXPos {
+ s.SetPos(firstPos)
+ firstPos = src.NoXPos
+ }
+ // let the backend handle it
+ thearch.SSAGenValue(&s, v)
+ }
+
+ if Ctxt.Flag_locationlists {
+ valueToProgAfter[v.ID] = s.pp.next
+ }
+
+ if f.PrintOrHtmlSSA {
+ for ; x != s.pp.next; x = x.Link {
+ progToValue[x] = v
+ }
+ }
+ }
+ // If this is an empty infinite loop, stick a hardware NOP in there so that debuggers are less confused.
+ if s.bstart[b.ID] == s.pp.next && len(b.Succs) == 1 && b.Succs[0].Block() == b {
+ p := thearch.Ginsnop(s.pp)
+ p.Pos = p.Pos.WithIsStmt()
+ if b.Pos == src.NoXPos {
+ b.Pos = p.Pos // It needs a file, otherwise a no-file non-zero line causes confusion. See #35652.
+ if b.Pos == src.NoXPos {
+ b.Pos = pp.Text.Pos // Sometimes p.Pos is empty. See #35695.
+ }
+ }
+ b.Pos = b.Pos.WithBogusLine() // Debuggers are not good about infinite loops, force a change in line number
+ }
+ // Emit control flow instructions for block
+ var next *ssa.Block
+ 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 := s.pp.next
+ s.SetPos(b.Pos)
+ thearch.SSAGenBlock(&s, b, next)
+ if f.PrintOrHtmlSSA {
+ for ; x != s.pp.next; x = x.Link {
+ progToBlock[x] = b
+ }
+ }
+ }
+ if f.Blocks[len(f.Blocks)-1].Kind == ssa.BlockExit {
+ // We need the return address of a panic call to
+ // still be inside the function in question. So if
+ // it ends in a call which doesn't return, add a
+ // nop (which will never execute) after the call.
+ thearch.Ginsnop(pp)
+ }
+ if openDeferInfo != nil {
+ // When doing open-coded defers, generate a disconnected call to
+ // deferreturn and a return. This will be used to during panic
+ // recovery to unwind the stack and return back to the runtime.
+ s.pp.nextLive = s.livenessMap.deferreturn
+ gencallret(pp, Deferreturn)
+ }
+
+ if inlMarks != nil {
+ // We have some inline marks. Try to find other instructions we're
+ // going to emit anyway, and use those instructions instead of the
+ // inline marks.
+ for p := pp.Text; p != nil; p = p.Link {
+ if p.As == obj.ANOP || p.As == obj.AFUNCDATA || p.As == obj.APCDATA || p.As == obj.ATEXT || p.As == obj.APCALIGN || thearch.LinkArch.Family == sys.Wasm {
+ // Don't use 0-sized instructions as inline marks, because we need
+ // to identify inline mark instructions by pc offset.
+ // (Some of these instructions are sometimes zero-sized, sometimes not.
+ // We must not use anything that even might be zero-sized.)
+ // TODO: are there others?
+ continue
+ }
+ if _, ok := inlMarks[p]; ok {
+ // Don't use inline marks themselves. We don't know
+ // whether they will be zero-sized or not yet.
+ continue
+ }
+ pos := p.Pos.AtColumn1()
+ s := inlMarksByPos[pos]
+ if len(s) == 0 {
+ continue
+ }
+ for _, m := range s {
+ // We found an instruction with the same source position as
+ // some of the inline marks.
+ // Use this instruction instead.
+ p.Pos = p.Pos.WithIsStmt() // promote position to a statement
+ pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[m])
+ // Make the inline mark a real nop, so it doesn't generate any code.
+ m.As = obj.ANOP
+ m.Pos = src.NoXPos
+ m.From = obj.Addr{}
+ m.To = obj.Addr{}
+ }
+ delete(inlMarksByPos, pos)
+ }
+ // Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction).
+ for _, p := range inlMarkList {
+ if p.As != obj.ANOP {
+ pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[p])
+ }
+ }
+ }
+
+ if Ctxt.Flag_locationlists {
+ e.curfn.Func.DebugInfo = ssa.BuildFuncDebug(Ctxt, f, Debug_locationlist > 1, stackOffset)
+ bstart := s.bstart
+ // Note that at this moment, Prog.Pc is a sequence number; it's
+ // not a real PC until after assembly, so this mapping has to
+ // be done later.
+ e.curfn.Func.DebugInfo.GetPC = func(b, v ssa.ID) int64 {
+ switch v {
+ case ssa.BlockStart.ID:
+ if b == f.Entry.ID {
+ return 0 // Start at the very beginning, at the assembler-generated prologue.
+ // this should only happen for function args (ssa.OpArg)
+ }
+ return bstart[b].Pc
+ case ssa.BlockEnd.ID:
+ return e.curfn.Func.lsym.Size
+ default:
+ return valueToProgAfter[v].Pc
+ }
+ }
+ }
+
+ // Resolve branches, and relax DefaultStmt into NotStmt
+ for _, br := range s.Branches {
+ br.P.To.SetTarget(s.bstart[br.B.ID])
+ if br.P.Pos.IsStmt() != src.PosIsStmt {
+ br.P.Pos = br.P.Pos.WithNotStmt()
+ } else if v0 := br.B.FirstPossibleStmtValue(); v0 != nil && v0.Pos.Line() == br.P.Pos.Line() && v0.Pos.IsStmt() == src.PosIsStmt {
+ br.P.Pos = br.P.Pos.WithNotStmt()
+ }
+
+ }
+
+ if e.log { // spew to stdout
+ filename := ""
+ for p := pp.Text; p != nil; p = p.Link {
+ if p.Pos.IsKnown() && p.InnermostFilename() != filename {
+ filename = p.InnermostFilename()
+ f.Logf("# %s\n", filename)
+ }
+
+ var s string
+ if v, ok := progToValue[p]; ok {
+ s = v.String()
+ } else if b, ok := progToBlock[p]; ok {
+ s = b.String()
+ } else {
+ s = " " // most value and branch strings are 2-3 characters long
+ }
+ f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString())
+ }
+ }
+ if f.HTMLWriter != nil { // spew to ssa.html
+ var buf bytes.Buffer
+ buf.WriteString("<code>")
+ buf.WriteString("<dl class=\"ssa-gen\">")
+ filename := ""
+ for p := pp.Text; p != nil; p = p.Link {
+ // Don't spam every line with the file name, which is often huge.
+ // Only print changes, and "unknown" is not a change.
+ if p.Pos.IsKnown() && p.InnermostFilename() != filename {
+ filename = p.InnermostFilename()
+ buf.WriteString("<dt class=\"ssa-prog-src\"></dt><dd class=\"ssa-prog\">")
+ buf.WriteString(html.EscapeString("# " + filename))
+ buf.WriteString("</dd>")
+ }
+
+ buf.WriteString("<dt class=\"ssa-prog-src\">")
+ if v, ok := progToValue[p]; ok {
+ buf.WriteString(v.HTML())
+ } else if b, ok := progToBlock[p]; ok {
+ buf.WriteString("<b>" + b.HTML() + "</b>")
+ }
+ buf.WriteString("</dt>")
+ buf.WriteString("<dd class=\"ssa-prog\">")
+ buf.WriteString(fmt.Sprintf("%.5d <span class=\"l%v line-number\">(%s)</span> %s", p.Pc, p.InnermostLineNumber(), p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString())))
+ buf.WriteString("</dd>")
+ }
+ buf.WriteString("</dl>")
+ buf.WriteString("</code>")
+ f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
+ }
+
+ defframe(&s, e)
+
+ f.HTMLWriter.Close()
+ f.HTMLWriter = nil
+}
+
+func defframe(s *SSAGenState, e *ssafn) {
+ pp := s.pp
+
+ frame := Rnd(s.maxarg+e.stksize, int64(Widthreg))
+ if thearch.PadFrame != nil {
+ frame = thearch.PadFrame(frame)
+ }
+
+ // Fill in argument and frame size.
+ pp.Text.To.Type = obj.TYPE_TEXTSIZE
+ pp.Text.To.Val = int32(Rnd(e.curfn.Type.ArgWidth(), int64(Widthreg)))
+ pp.Text.To.Offset = frame
+
+ // Insert code to zero ambiguously live variables so that the
+ // garbage collector only sees initialized values when it
+ // looks for pointers.
+ p := pp.Text
+ var lo, hi int64
+
+ // Opaque state for backend to use. Current backends use it to
+ // keep track of which helper registers have been zeroed.
+ var state uint32
+
+ // Iterate through declarations. They are sorted in decreasing Xoffset order.
+ for _, n := range e.curfn.Func.Dcl {
+ if !n.Name.Needzero() {
+ continue
+ }
+ if n.Class() != PAUTO {
+ e.Fatalf(n.Pos, "needzero class %d", n.Class())
+ }
+ if n.Type.Size()%int64(Widthptr) != 0 || n.Xoffset%int64(Widthptr) != 0 || n.Type.Size() == 0 {
+ e.Fatalf(n.Pos, "var %L has size %d offset %d", n, n.Type.Size(), n.Xoffset)
+ }
+
+ if lo != hi && n.Xoffset+n.Type.Size() >= lo-int64(2*Widthreg) {
+ // Merge with range we already have.
+ lo = n.Xoffset
+ continue
+ }
+
+ // Zero old range
+ p = thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
+
+ // Set new range.
+ lo = n.Xoffset
+ hi = lo + n.Type.Size()
+ }
+
+ // Zero final range.
+ thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
+}
+
+// For generating consecutive jump instructions to model a specific branching
+type IndexJump struct {
+ Jump obj.As
+ Index int
+}
+
+func (s *SSAGenState) oneJump(b *ssa.Block, jump *IndexJump) {
+ p := s.Br(jump.Jump, b.Succs[jump.Index].Block())
+ p.Pos = b.Pos
+}
+
+// CombJump generates combinational instructions (2 at present) for a block jump,
+// thereby the behaviour of non-standard condition codes could be simulated
+func (s *SSAGenState) CombJump(b, next *ssa.Block, jumps *[2][2]IndexJump) {
+ switch next {
+ case b.Succs[0].Block():
+ s.oneJump(b, &jumps[0][0])
+ s.oneJump(b, &jumps[0][1])
+ case b.Succs[1].Block():
+ s.oneJump(b, &jumps[1][0])
+ s.oneJump(b, &jumps[1][1])
+ default:
+ var q *obj.Prog
+ if b.Likely != ssa.BranchUnlikely {
+ s.oneJump(b, &jumps[1][0])
+ s.oneJump(b, &jumps[1][1])
+ q = s.Br(obj.AJMP, b.Succs[1].Block())
+ } else {
+ s.oneJump(b, &jumps[0][0])
+ s.oneJump(b, &jumps[0][1])
+ q = s.Br(obj.AJMP, b.Succs[0].Block())
+ }
+ q.Pos = b.Pos
+ }
+}
+
+// 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 && a.Type != obj.TYPE_ADDR {
+ v.Fatalf("bad AddAux addr %v", a)
+ }
+ // add integer offset
+ a.Offset += offset
+
+ // If no additional symbol offset, we're done.
+ if v.Aux == nil {
+ return
+ }
+ // Add symbol's offset from its base register.
+ switch n := v.Aux.(type) {
+ case *ssa.AuxCall:
+ a.Name = obj.NAME_EXTERN
+ a.Sym = n.Fn
+ case *obj.LSym:
+ a.Name = obj.NAME_EXTERN
+ a.Sym = n
+ case *Node:
+ if n.Class() == PPARAM || n.Class() == PPARAMOUT {
+ a.Name = obj.NAME_PARAM
+ a.Sym = n.Orig.Sym.Linksym()
+ a.Offset += n.Xoffset
+ break
+ }
+ a.Name = obj.NAME_AUTO
+ a.Sym = n.Sym.Linksym()
+ a.Offset += n.Xoffset
+ default:
+ v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
+ }
+}
+
+// extendIndex extends v to a full int width.
+// panic with the given kind if v does not fit in an int (only on 32-bit archs).
+func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
+ size := idx.Type.Size()
+ if size == s.config.PtrSize {
+ return idx
+ }
+ if size > s.config.PtrSize {
+ // truncate 64-bit indexes on 32-bit pointer archs. Test the
+ // high word and branch to out-of-bounds failure if it is not 0.
+ var lo *ssa.Value
+ if idx.Type.IsSigned() {
+ lo = s.newValue1(ssa.OpInt64Lo, types.Types[TINT], idx)
+ } else {
+ lo = s.newValue1(ssa.OpInt64Lo, types.Types[TUINT], idx)
+ }
+ if bounded || Debug.B != 0 {
+ return lo
+ }
+ bNext := s.f.NewBlock(ssa.BlockPlain)
+ bPanic := s.f.NewBlock(ssa.BlockExit)
+ hi := s.newValue1(ssa.OpInt64Hi, types.Types[TUINT32], idx)
+ cmp := s.newValue2(ssa.OpEq32, types.Types[TBOOL], hi, s.constInt32(types.Types[TUINT32], 0))
+ if !idx.Type.IsSigned() {
+ switch kind {
+ case ssa.BoundsIndex:
+ kind = ssa.BoundsIndexU
+ case ssa.BoundsSliceAlen:
+ kind = ssa.BoundsSliceAlenU
+ case ssa.BoundsSliceAcap:
+ kind = ssa.BoundsSliceAcapU
+ case ssa.BoundsSliceB:
+ kind = ssa.BoundsSliceBU
+ case ssa.BoundsSlice3Alen:
+ kind = ssa.BoundsSlice3AlenU
+ case ssa.BoundsSlice3Acap:
+ kind = ssa.BoundsSlice3AcapU
+ case ssa.BoundsSlice3B:
+ kind = ssa.BoundsSlice3BU
+ case ssa.BoundsSlice3C:
+ kind = ssa.BoundsSlice3CU
+ }
+ }
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(cmp)
+ b.Likely = ssa.BranchLikely
+ b.AddEdgeTo(bNext)
+ b.AddEdgeTo(bPanic)
+
+ s.startBlock(bPanic)
+ mem := s.newValue4I(ssa.OpPanicExtend, types.TypeMem, int64(kind), hi, lo, len, s.mem())
+ s.endBlock().SetControl(mem)
+ s.startBlock(bNext)
+
+ return lo
+ }
+
+ // Extend value to the required size
+ var op ssa.Op
+ if idx.Type.IsSigned() {
+ switch 10*size + s.config.PtrSize {
+ case 14:
+ op = ssa.OpSignExt8to32
+ case 18:
+ op = ssa.OpSignExt8to64
+ case 24:
+ op = ssa.OpSignExt16to32
+ case 28:
+ op = ssa.OpSignExt16to64
+ case 48:
+ op = ssa.OpSignExt32to64
+ default:
+ s.Fatalf("bad signed index extension %s", idx.Type)
+ }
+ } else {
+ switch 10*size + s.config.PtrSize {
+ case 14:
+ op = ssa.OpZeroExt8to32
+ case 18:
+ op = ssa.OpZeroExt8to64
+ case 24:
+ op = ssa.OpZeroExt16to32
+ case 28:
+ op = ssa.OpZeroExt16to64
+ case 48:
+ op = ssa.OpZeroExt32to64
+ default:
+ s.Fatalf("bad unsigned index extension %s", idx.Type)
+ }
+ }
+ return s.newValue1(op, types.Types[TINT], idx)
+}
+
+// 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 @ %s, but arg %v @ %s\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)
+ }
+}
+
+// AutoVar returns a *Node and int64 representing the auto variable and offset within it
+// where v should be spilled.
+func AutoVar(v *ssa.Value) (*Node, int64) {
+ loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
+ if v.Type.Size() > loc.Type.Size() {
+ v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
+ }
+ return loc.N.(*Node), loc.Off
+}
+
+func AddrAuto(a *obj.Addr, v *ssa.Value) {
+ n, off := AutoVar(v)
+ a.Type = obj.TYPE_MEM
+ a.Sym = n.Sym.Linksym()
+ a.Reg = int16(thearch.REGSP)
+ 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.Sym = s.ScratchFpMem.Sym.Linksym()
+ a.Reg = int16(thearch.REGSP)
+ a.Offset = s.ScratchFpMem.Xoffset
+}
+
+// Call returns a new CALL instruction for the SSA value v.
+// It uses PrepareCall to prepare the call.
+func (s *SSAGenState) Call(v *ssa.Value) *obj.Prog {
+ pPosIsStmt := s.pp.pos.IsStmt() // The statement-ness fo the call comes from ssaGenState
+ s.PrepareCall(v)
+
+ p := s.Prog(obj.ACALL)
+ if pPosIsStmt == src.PosIsStmt {
+ p.Pos = v.Pos.WithIsStmt()
+ } else {
+ p.Pos = v.Pos.WithNotStmt()
+ }
+ if sym, ok := v.Aux.(*ssa.AuxCall); ok && sym.Fn != nil {
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = sym.Fn
+ } else {
+ // TODO(mdempsky): Can these differences be eliminated?
+ switch thearch.LinkArch.Family {
+ case sys.AMD64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X, sys.Wasm:
+ p.To.Type = obj.TYPE_REG
+ case sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64:
+ p.To.Type = obj.TYPE_MEM
+ default:
+ Fatalf("unknown indirect call family")
+ }
+ p.To.Reg = v.Args[0].Reg()
+ }
+ return p
+}
+
+// PrepareCall prepares to emit a CALL instruction for v and does call-related bookkeeping.
+// It must be called immediately before emitting the actual CALL instruction,
+// since it emits PCDATA for the stack map at the call (calls are safe points).
+func (s *SSAGenState) PrepareCall(v *ssa.Value) {
+ idx := s.livenessMap.Get(v)
+ if !idx.StackMapValid() {
+ // See Liveness.hasStackMap.
+ if sym, ok := v.Aux.(*ssa.AuxCall); !ok || !(sym.Fn == typedmemclr || sym.Fn == typedmemmove) {
+ Fatalf("missing stack map index for %v", v.LongString())
+ }
+ }
+
+ call, ok := v.Aux.(*ssa.AuxCall)
+
+ if ok && call.Fn == Deferreturn {
+ // Deferred calls will appear to be returning to
+ // the CALL deferreturn(SB) that we are about to emit.
+ // However, the stack trace code will show the line
+ // of the instruction byte before the return PC.
+ // To avoid that being an unrelated instruction,
+ // insert an actual hardware NOP that will have the right line number.
+ // This is different from obj.ANOP, which is a virtual no-op
+ // that doesn't make it into the instruction stream.
+ thearch.Ginsnopdefer(s.pp)
+ }
+
+ if ok {
+ // Record call graph information for nowritebarrierrec
+ // analysis.
+ if nowritebarrierrecCheck != nil {
+ nowritebarrierrecCheck.recordCall(s.pp.curfn, call.Fn, v.Pos)
+ }
+ }
+
+ if s.maxarg < v.AuxInt {
+ s.maxarg = v.AuxInt
+ }
+}
+
+// UseArgs records the fact that an instruction needs a certain amount of
+// callee args space for its use.
+func (s *SSAGenState) UseArgs(n int64) {
+ if s.maxarg < n {
+ s.maxarg = n
+ }
+}
+
+// fieldIdx finds the index of the field referred to by the ODOT node n.
+func fieldIdx(n *Node) int {
+ t := n.Left.Type
+ f := n.Sym
+ if !t.IsStruct() {
+ panic("ODOT's LHS is not a struct")
+ }
+
+ var i int
+ for _, t1 := range t.Fields().Slice() {
+ if t1.Sym != f {
+ i++
+ continue
+ }
+ if t1.Offset != n.Xoffset {
+ panic("field offset doesn't match")
+ }
+ return i
+ }
+ panic(fmt.Sprintf("can't find field in expr %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.
+}
+
+// ssafn holds frontend information about a function that the backend is processing.
+// It also exports a bunch of compiler services for the ssa backend.
+type ssafn struct {
+ curfn *Node
+ strings map[string]*obj.LSym // map from constant string to data symbols
+ scratchFpMem *Node // temp for floating point register / memory moves on some architectures
+ stksize int64 // stack size for current frame
+ stkptrsize int64 // prefix of stack containing pointers
+ log bool // print ssa debug to the stdout
+}
+
+// StringData returns a symbol which
+// is the data component of a global string constant containing s.
+func (e *ssafn) StringData(s string) *obj.LSym {
+ if aux, ok := e.strings[s]; ok {
+ return aux
+ }
+ if e.strings == nil {
+ e.strings = make(map[string]*obj.LSym)
+ }
+ data := stringsym(e.curfn.Pos, s)
+ e.strings[s] = data
+ return data
+}
+
+func (e *ssafn) Auto(pos src.XPos, t *types.Type) ssa.GCNode {
+ n := tempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
+ return n
+}
+
+func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+ ptrType := types.NewPtr(types.Types[TUINT8])
+ lenType := types.Types[TINT]
+ // Split this string up into two separate variables.
+ p := e.SplitSlot(&name, ".ptr", 0, ptrType)
+ l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
+ return p, l
+}
+
+func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+ n := name.N.(*Node)
+ u := types.Types[TUINTPTR]
+ t := types.NewPtr(types.Types[TUINT8])
+ // Split this interface up into two separate variables.
+ f := ".itab"
+ if n.Type.IsEmptyInterface() {
+ f = ".type"
+ }
+ c := e.SplitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
+ d := e.SplitSlot(&name, ".data", u.Size(), t)
+ return c, d
+}
+
+func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
+ ptrType := types.NewPtr(name.Type.Elem())
+ lenType := types.Types[TINT]
+ p := e.SplitSlot(&name, ".ptr", 0, ptrType)
+ l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
+ c := e.SplitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
+ return p, l, c
+}
+
+func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+ s := name.Type.Size() / 2
+ var t *types.Type
+ if s == 8 {
+ t = types.Types[TFLOAT64]
+ } else {
+ t = types.Types[TFLOAT32]
+ }
+ r := e.SplitSlot(&name, ".real", 0, t)
+ i := e.SplitSlot(&name, ".imag", t.Size(), t)
+ return r, i
+}
+
+func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+ var t *types.Type
+ if name.Type.IsSigned() {
+ t = types.Types[TINT32]
+ } else {
+ t = types.Types[TUINT32]
+ }
+ if thearch.LinkArch.ByteOrder == binary.BigEndian {
+ return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
+ }
+ return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[TUINT32])
+}
+
+func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
+ st := name.Type
+ // Note: the _ field may appear several times. But
+ // have no fear, identically-named but distinct Autos are
+ // ok, albeit maybe confusing for a debugger.
+ return e.SplitSlot(&name, "."+st.FieldName(i), st.FieldOff(i), st.FieldType(i))
+}
+
+func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
+ n := name.N.(*Node)
+ at := name.Type
+ if at.NumElem() != 1 {
+ e.Fatalf(n.Pos, "bad array size")
+ }
+ et := at.Elem()
+ return e.SplitSlot(&name, "[0]", 0, et)
+}
+
+func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
+ return itabsym(it, offset)
+}
+
+// SplitSlot returns a slot representing the data of parent starting at offset.
+func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
+ node := parent.N.(*Node)
+
+ if node.Class() != PAUTO || node.Name.Addrtaken() {
+ // addressed things and non-autos retain their parents (i.e., cannot truly be split)
+ return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
+ }
+
+ s := &types.Sym{Name: node.Sym.Name + suffix, Pkg: localpkg}
+
+ n := &Node{
+ Name: new(Name),
+ Op: ONAME,
+ Pos: parent.N.(*Node).Pos,
+ }
+ n.Orig = n
+
+ s.Def = asTypesNode(n)
+ asNode(s.Def).Name.SetUsed(true)
+ n.Sym = s
+ n.Type = t
+ n.SetClass(PAUTO)
+ n.Esc = EscNever
+ n.Name.Curfn = e.curfn
+ e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
+ dowidth(t)
+ return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
+}
+
+func (e *ssafn) CanSSA(t *types.Type) bool {
+ return canSSAType(t)
+}
+
+func (e *ssafn) Line(pos src.XPos) string {
+ return linestr(pos)
+}
+
+// Log logs a message from the compiler.
+func (e *ssafn) Logf(msg string, args ...interface{}) {
+ if e.log {
+ fmt.Printf(msg, args...)
+ }
+}
+
+func (e *ssafn) Log() bool {
+ return e.log
+}
+
+// Fatal reports a compiler error and exits.
+func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...interface{}) {
+ lineno = pos
+ nargs := append([]interface{}{e.curfn.funcname()}, args...)
+ Fatalf("'%s': "+msg, nargs...)
+}
+
+// Warnl reports a "warning", which is usually flag-triggered
+// logging output for the benefit of tests.
+func (e *ssafn) Warnl(pos src.XPos, fmt_ string, args ...interface{}) {
+ Warnl(pos, fmt_, args...)
+}
+
+func (e *ssafn) Debug_checknil() bool {
+ return Debug_checknil != 0
+}
+
+func (e *ssafn) UseWriteBarrier() bool {
+ return use_writebarrier
+}
+
+func (e *ssafn) Syslook(name string) *obj.LSym {
+ switch name {
+ case "goschedguarded":
+ return goschedguarded
+ case "writeBarrier":
+ return writeBarrier
+ case "gcWriteBarrier":
+ return gcWriteBarrier
+ case "typedmemmove":
+ return typedmemmove
+ case "typedmemclr":
+ return typedmemclr
+ }
+ e.Fatalf(src.NoXPos, "unknown Syslook func %v", name)
+ return nil
+}
+
+func (e *ssafn) SetWBPos(pos src.XPos) {
+ e.curfn.Func.setWBPos(pos)
+}
+
+func (e *ssafn) MyImportPath() string {
+ return myimportpath
+}
+
+func (n *Node) Typ() *types.Type {
+ return n.Type
+}
+func (n *Node) StorageClass() ssa.StorageClass {
+ switch n.Class() {
+ case PPARAM:
+ return ssa.ClassParam
+ case PPARAMOUT:
+ return ssa.ClassParamOut
+ case PAUTO:
+ return ssa.ClassAuto
+ default:
+ Fatalf("untranslatable storage class for %v: %s", n, n.Class())
+ return 0
+ }
+}
+
+func clobberBase(n *Node) *Node {
+ if n.Op == ODOT && n.Left.Type.NumFields() == 1 {
+ return clobberBase(n.Left)
+ }
+ if n.Op == OINDEX && n.Left.Type.IsArray() && n.Left.Type.NumElem() == 1 {
+ return clobberBase(n.Left)
+ }
+ return n
+}
diff --git a/src/cmd/compile/internal/gc/ssa_test.go b/src/cmd/compile/internal/gc/ssa_test.go
new file mode 100644
index 0000000..7f7c946
--- /dev/null
+++ b/src/cmd/compile/internal/gc/ssa_test.go
@@ -0,0 +1,191 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+// runGenTest runs a test-generator, then runs the generated test.
+// Generated test can either fail in compilation or execution.
+// The environment variable parameter(s) is passed to the run
+// of the generated test.
+func runGenTest(t *testing.T, filename, tmpname string, ev ...string) {
+ testenv.MustHaveGoRun(t)
+ gotool := testenv.GoToolPath(t)
+ var stdout, stderr bytes.Buffer
+ cmd := exec.Command(gotool, "run", filepath.Join("testdata", filename))
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+ if err := cmd.Run(); err != nil {
+ t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr)
+ }
+ // Write stdout into a temporary file
+ tmpdir, ok := ioutil.TempDir("", tmpname)
+ if ok != nil {
+ t.Fatalf("Failed to create temporary directory")
+ }
+ defer os.RemoveAll(tmpdir)
+
+ rungo := filepath.Join(tmpdir, "run.go")
+ ok = ioutil.WriteFile(rungo, stdout.Bytes(), 0600)
+ if ok != nil {
+ t.Fatalf("Failed to create temporary file " + rungo)
+ }
+
+ stdout.Reset()
+ stderr.Reset()
+ cmd = exec.Command(gotool, "run", "-gcflags=-d=ssa/check/on", rungo)
+ cmd.Stdout = &stdout
+ cmd.Stderr = &stderr
+ cmd.Env = append(cmd.Env, ev...)
+ err := cmd.Run()
+ if err != nil {
+ t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr)
+ }
+ if s := stderr.String(); s != "" {
+ t.Errorf("Stderr = %s\nWant empty", s)
+ }
+ if s := stdout.String(); s != "" {
+ t.Errorf("Stdout = %s\nWant empty", s)
+ }
+}
+
+func TestGenFlowGraph(t *testing.T) {
+ if testing.Short() {
+ t.Skip("not run in short mode.")
+ }
+ runGenTest(t, "flowgraph_generator1.go", "ssa_fg_tmp1")
+}
+
+// TestCode runs all the tests in the testdata directory as subtests.
+// These tests are special because we want to run them with different
+// compiler flags set (and thus they can't just be _test.go files in
+// this directory).
+func TestCode(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ gotool := testenv.GoToolPath(t)
+
+ // Make a temporary directory to work in.
+ tmpdir, err := ioutil.TempDir("", "TestCode")
+ if err != nil {
+ t.Fatalf("Failed to create temporary directory: %v", err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ // Find all the test functions (and the files containing them).
+ var srcs []string // files containing Test functions
+ type test struct {
+ name string // TestFoo
+ usesFloat bool // might use float operations
+ }
+ var tests []test
+ files, err := ioutil.ReadDir("testdata")
+ if err != nil {
+ t.Fatalf("can't read testdata directory: %v", err)
+ }
+ for _, f := range files {
+ if !strings.HasSuffix(f.Name(), "_test.go") {
+ continue
+ }
+ text, err := ioutil.ReadFile(filepath.Join("testdata", f.Name()))
+ if err != nil {
+ t.Fatalf("can't read testdata/%s: %v", f.Name(), err)
+ }
+ fset := token.NewFileSet()
+ code, err := parser.ParseFile(fset, f.Name(), text, 0)
+ if err != nil {
+ t.Fatalf("can't parse testdata/%s: %v", f.Name(), err)
+ }
+ srcs = append(srcs, filepath.Join("testdata", f.Name()))
+ foundTest := false
+ for _, d := range code.Decls {
+ fd, ok := d.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ if !strings.HasPrefix(fd.Name.Name, "Test") {
+ continue
+ }
+ if fd.Recv != nil {
+ continue
+ }
+ if fd.Type.Results != nil {
+ continue
+ }
+ if len(fd.Type.Params.List) != 1 {
+ continue
+ }
+ p := fd.Type.Params.List[0]
+ if len(p.Names) != 1 {
+ continue
+ }
+ s, ok := p.Type.(*ast.StarExpr)
+ if !ok {
+ continue
+ }
+ sel, ok := s.X.(*ast.SelectorExpr)
+ if !ok {
+ continue
+ }
+ base, ok := sel.X.(*ast.Ident)
+ if !ok {
+ continue
+ }
+ if base.Name != "testing" {
+ continue
+ }
+ if sel.Sel.Name != "T" {
+ continue
+ }
+ // Found a testing function.
+ tests = append(tests, test{name: fd.Name.Name, usesFloat: bytes.Contains(text, []byte("float"))})
+ foundTest = true
+ }
+ if !foundTest {
+ t.Fatalf("test file testdata/%s has no tests in it", f.Name())
+ }
+ }
+
+ flags := []string{""}
+ if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" {
+ flags = append(flags, ",softfloat")
+ }
+ for _, flag := range flags {
+ args := []string{"test", "-c", "-gcflags=-d=ssa/check/on" + flag, "-o", filepath.Join(tmpdir, "code.test")}
+ args = append(args, srcs...)
+ out, err := exec.Command(gotool, args...).CombinedOutput()
+ if err != nil || len(out) != 0 {
+ t.Fatalf("Build failed: %v\n%s\n", err, out)
+ }
+
+ // Now we have a test binary. Run it with all the tests as subtests of this one.
+ for _, test := range tests {
+ test := test
+ if flag == ",softfloat" && !test.usesFloat {
+ // No point in running the soft float version if the test doesn't use floats.
+ continue
+ }
+ t.Run(fmt.Sprintf("%s%s", test.name[4:], flag), func(t *testing.T) {
+ out, err := exec.Command(filepath.Join(tmpdir, "code.test"), "-test.run="+test.name).CombinedOutput()
+ if err != nil || string(out) != "PASS\n" {
+ t.Errorf("Failed:\n%s\n", out)
+ }
+ })
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
new file mode 100644
index 0000000..defefd7
--- /dev/null
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -0,0 +1,1918 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+ "crypto/md5"
+ "encoding/binary"
+ "fmt"
+ "os"
+ "runtime/debug"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "unicode"
+ "unicode/utf8"
+)
+
+type Error struct {
+ pos src.XPos
+ msg string
+}
+
+var errors []Error
+
+// largeStack is info about a function whose stack frame is too large (rare).
+type largeStack struct {
+ locals int64
+ args int64
+ callee int64
+ pos src.XPos
+}
+
+var (
+ largeStackFramesMu sync.Mutex // protects largeStackFrames
+ largeStackFrames []largeStack
+)
+
+func errorexit() {
+ flusherrors()
+ if outfile != "" {
+ os.Remove(outfile)
+ }
+ os.Exit(2)
+}
+
+func adderrorname(n *Node) {
+ if n.Op != ODOT {
+ return
+ }
+ old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
+ if len(errors) > 0 && errors[len(errors)-1].pos.Line() == n.Pos.Line() && errors[len(errors)-1].msg == old {
+ errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n)
+ }
+}
+
+func adderr(pos src.XPos, format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ // Only add the position if know the position.
+ // See issue golang.org/issue/11361.
+ if pos.IsKnown() {
+ msg = fmt.Sprintf("%v: %s", linestr(pos), msg)
+ }
+ errors = append(errors, Error{
+ pos: pos,
+ msg: msg + "\n",
+ })
+}
+
+// byPos sorts errors by source position.
+type byPos []Error
+
+func (x byPos) Len() int { return len(x) }
+func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
+func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+// flusherrors sorts errors seen so far by line number, prints them to stdout,
+// and empties the errors array.
+func flusherrors() {
+ Ctxt.Bso.Flush()
+ if len(errors) == 0 {
+ return
+ }
+ sort.Stable(byPos(errors))
+ for i, err := range errors {
+ if i == 0 || err.msg != errors[i-1].msg {
+ fmt.Printf("%s", err.msg)
+ }
+ }
+ errors = errors[:0]
+}
+
+func hcrash() {
+ if Debug.h != 0 {
+ flusherrors()
+ if outfile != "" {
+ os.Remove(outfile)
+ }
+ var x *int
+ *x = 0
+ }
+}
+
+func linestr(pos src.XPos) string {
+ return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1)
+}
+
+// lasterror keeps track of the most recently issued error.
+// It is used to avoid multiple error messages on the same
+// line.
+var lasterror struct {
+ syntax src.XPos // source position of last syntax error
+ other src.XPos // source position of last non-syntax error
+ msg string // error message of last non-syntax error
+}
+
+// sameline reports whether two positions a, b are on the same line.
+func sameline(a, b src.XPos) bool {
+ p := Ctxt.PosTable.Pos(a)
+ q := Ctxt.PosTable.Pos(b)
+ return p.Base() == q.Base() && p.Line() == q.Line()
+}
+
+func yyerrorl(pos src.XPos, format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+
+ if strings.HasPrefix(msg, "syntax error") {
+ nsyntaxerrors++
+ // only one syntax error per line, no matter what error
+ if sameline(lasterror.syntax, pos) {
+ return
+ }
+ lasterror.syntax = pos
+ } else {
+ // only one of multiple equal non-syntax errors per line
+ // (flusherrors shows only one of them, so we filter them
+ // here as best as we can (they may not appear in order)
+ // so that we don't count them here and exit early, and
+ // then have nothing to show for.)
+ if sameline(lasterror.other, pos) && lasterror.msg == msg {
+ return
+ }
+ lasterror.other = pos
+ lasterror.msg = msg
+ }
+
+ adderr(pos, "%s", msg)
+
+ hcrash()
+ nerrors++
+ if nsavederrors+nerrors >= 10 && Debug.e == 0 {
+ flusherrors()
+ fmt.Printf("%v: too many errors\n", linestr(pos))
+ errorexit()
+ }
+}
+
+func yyerrorv(lang string, format string, args ...interface{}) {
+ what := fmt.Sprintf(format, args...)
+ yyerrorl(lineno, "%s requires %s or later (-lang was set to %s; check go.mod)", what, lang, flag_lang)
+}
+
+func yyerror(format string, args ...interface{}) {
+ yyerrorl(lineno, format, args...)
+}
+
+func Warn(fmt_ string, args ...interface{}) {
+ Warnl(lineno, fmt_, args...)
+}
+
+func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
+ adderr(line, fmt_, args...)
+ if Debug.m != 0 {
+ flusherrors()
+ }
+}
+
+func Fatalf(fmt_ string, args ...interface{}) {
+ flusherrors()
+
+ if Debug_panic != 0 || nsavederrors+nerrors == 0 {
+ 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(objabi.Version, "go") {
+ fmt.Printf("\n")
+ fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
+ fmt.Printf("https://golang.org/issue/new\n")
+ } else {
+ // Not a release; dump a stack trace, too.
+ fmt.Println()
+ os.Stdout.Write(debug.Stack())
+ fmt.Println()
+ }
+ }
+
+ hcrash()
+ errorexit()
+}
+
+// hasUniquePos reports whether n has a unique position that can be
+// used for reporting error messages.
+//
+// It's primarily used to distinguish references to named objects,
+// whose Pos will point back to their declaration position rather than
+// their usage position.
+func hasUniquePos(n *Node) bool {
+ switch n.Op {
+ case ONAME, OPACK:
+ return false
+ case OLITERAL, OTYPE:
+ if n.Sym != nil {
+ return false
+ }
+ }
+
+ if !n.Pos.IsKnown() {
+ if Debug.K != 0 {
+ Warn("setlineno: unknown position (line 0)")
+ }
+ return false
+ }
+
+ return true
+}
+
+func setlineno(n *Node) src.XPos {
+ lno := lineno
+ if n != nil && hasUniquePos(n) {
+ lineno = n.Pos
+ }
+ return lno
+}
+
+func lookup(name string) *types.Sym {
+ return localpkg.Lookup(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) *types.Sym {
+ var buf [20]byte // plenty long enough for all current users
+ copy(buf[:], prefix)
+ b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
+ return localpkg.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) *types.Sym {
+ 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 lookupN(prefix, int(n))
+}
+
+// find all the exported symbols in package opkg
+// and make them available in the current package
+func importdot(opkg *types.Pkg, pack *Node) {
+ n := 0
+ for _, s := range opkg.Syms {
+ if s.Def == nil {
+ continue
+ }
+ if !types.IsExported(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
+ continue
+ }
+ s1 := lookup(s.Name)
+ if s1.Def != nil {
+ pkgerror := fmt.Sprintf("during import %q", opkg.Path)
+ redeclare(lineno, s1, pkgerror)
+ continue
+ }
+
+ s1.Def = s.Def
+ s1.Block = s.Block
+ if asNode(s1.Def).Name == nil {
+ Dump("s1def", asNode(s1.Def))
+ Fatalf("missing Name")
+ }
+ asNode(s1.Def).Name.Pack = pack
+ s1.Origpkg = opkg
+ n++
+ }
+
+ if n == 0 {
+ // can't possibly be used - there were no symbols
+ yyerrorl(pack.Pos, "imported and not used: %q", opkg.Path)
+ }
+}
+
+func nod(op Op, nleft, nright *Node) *Node {
+ return nodl(lineno, op, nleft, nright)
+}
+
+func nodl(pos src.XPos, op Op, nleft, nright *Node) *Node {
+ var n *Node
+ switch op {
+ case OCLOSURE, ODCLFUNC:
+ var x struct {
+ n Node
+ f Func
+ }
+ n = &x.n
+ n.Func = &x.f
+ case ONAME:
+ Fatalf("use newname instead")
+ case OLABEL, OPACK:
+ var x struct {
+ n Node
+ m Name
+ }
+ n = &x.n
+ n.Name = &x.m
+ default:
+ n = new(Node)
+ }
+ n.Op = op
+ n.Left = nleft
+ n.Right = nright
+ n.Pos = pos
+ n.Xoffset = BADWIDTH
+ n.Orig = n
+ return n
+}
+
+// newname returns a new ONAME Node associated with symbol s.
+func newname(s *types.Sym) *Node {
+ n := newnamel(lineno, s)
+ n.Name.Curfn = Curfn
+ return n
+}
+
+// newnamel returns a new ONAME Node associated with symbol s at position pos.
+// The caller is responsible for setting n.Name.Curfn.
+func newnamel(pos src.XPos, s *types.Sym) *Node {
+ if s == nil {
+ Fatalf("newnamel nil")
+ }
+
+ var x struct {
+ n Node
+ m Name
+ p Param
+ }
+ n := &x.n
+ n.Name = &x.m
+ n.Name.Param = &x.p
+
+ n.Op = ONAME
+ n.Pos = pos
+ n.Orig = n
+
+ n.Sym = s
+ return n
+}
+
+// nodSym makes a Node with Op op and with the Left field set to left
+// and the Sym field set to sym. This is for ODOT and friends.
+func nodSym(op Op, left *Node, sym *types.Sym) *Node {
+ return nodlSym(lineno, op, left, sym)
+}
+
+// nodlSym makes a Node with position Pos, 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 nodlSym(pos src.XPos, op Op, left *Node, sym *types.Sym) *Node {
+ n := nodl(pos, op, left, nil)
+ n.Sym = sym
+ return n
+}
+
+// rawcopy returns a shallow copy of n.
+// Note: copy or sepcopy (rather than rawcopy) is usually the
+// correct choice (see comment with Node.copy, below).
+func (n *Node) rawcopy() *Node {
+ copy := *n
+ return &copy
+}
+
+// sepcopy returns a separate shallow copy of n, with the copy's
+// Orig pointing to itself.
+func (n *Node) sepcopy() *Node {
+ copy := *n
+ copy.Orig = &copy
+ return &copy
+}
+
+// copy returns shallow copy of n and adjusts the copy's Orig if
+// necessary: In general, if n.Orig points to itself, the copy's
+// Orig should point to itself as well. Otherwise, if n is modified,
+// the copy's Orig node appears modified, too, and then doesn't
+// represent the original node anymore.
+// (This caused the wrong complit Op to be used when printing error
+// messages; see issues #26855, #27765).
+func (n *Node) copy() *Node {
+ copy := *n
+ if n.Orig == n {
+ copy.Orig = &copy
+ }
+ return &copy
+}
+
+// methcmp sorts methods by symbol.
+type methcmp []*types.Field
+
+func (x methcmp) Len() int { return len(x) }
+func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x methcmp) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) }
+
+func nodintconst(v int64) *Node {
+ u := new(Mpint)
+ u.SetInt64(v)
+ return nodlit(Val{u})
+}
+
+func nodnil() *Node {
+ return nodlit(Val{new(NilVal)})
+}
+
+func nodbool(b bool) *Node {
+ return nodlit(Val{b})
+}
+
+func nodstr(s string) *Node {
+ return nodlit(Val{s})
+}
+
+// treecopy recursively copies n, with the exception of
+// ONAME, OLITERAL, OTYPE, and ONONAME leaves.
+// If pos.IsKnown(), it sets the source position of newly
+// allocated nodes to pos.
+func treecopy(n *Node, pos src.XPos) *Node {
+ if n == nil {
+ return nil
+ }
+
+ switch n.Op {
+ default:
+ m := n.sepcopy()
+ m.Left = treecopy(n.Left, pos)
+ m.Right = treecopy(n.Right, pos)
+ m.List.Set(listtreecopy(n.List.Slice(), pos))
+ if pos.IsKnown() {
+ m.Pos = pos
+ }
+ if m.Name != nil && n.Op != ODCLFIELD {
+ Dump("treecopy", n)
+ Fatalf("treecopy Name")
+ }
+ return m
+
+ case OPACK:
+ // OPACK nodes are never valid in const value declarations,
+ // but allow them like any other declared symbol to avoid
+ // crashing (golang.org/issue/11361).
+ fallthrough
+
+ case ONAME, ONONAME, OLITERAL, OTYPE:
+ return n
+
+ }
+}
+
+// isNil reports whether n represents the universal untyped zero value "nil".
+func (n *Node) isNil() bool {
+ // Check n.Orig because constant propagation may produce typed nil constants,
+ // which don't exist in the Go spec.
+ return Isconst(n.Orig, CTNIL)
+}
+
+func isptrto(t *types.Type, et types.EType) bool {
+ if t == nil {
+ return false
+ }
+ if !t.IsPtr() {
+ return false
+ }
+ t = t.Elem()
+ if t == nil {
+ return false
+ }
+ if t.Etype != et {
+ return false
+ }
+ return true
+}
+
+func (n *Node) isBlank() bool {
+ if n == nil {
+ return false
+ }
+ return n.Sym.IsBlank()
+}
+
+// methtype returns the underlying type, if any,
+// that owns methods with receiver parameter t.
+// The result is either a named type or an anonymous struct.
+func methtype(t *types.Type) *types.Type {
+ if t == nil {
+ return nil
+ }
+
+ // Strip away pointer if it's there.
+ if t.IsPtr() {
+ if t.Sym != nil {
+ return nil
+ }
+ t = t.Elem()
+ if t == nil {
+ return nil
+ }
+ }
+
+ // Must be a named type or anonymous struct.
+ if t.Sym == nil && !t.IsStruct() {
+ return nil
+ }
+
+ // Check types.
+ if issimple[t.Etype] {
+ return t
+ }
+ switch t.Etype {
+ case TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRING, TSTRUCT:
+ return t
+ }
+ return nil
+}
+
+// Is type src assignment compatible to type dst?
+// If so, return op code to use in conversion.
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
+func assignop(src, dst *types.Type) (Op, string) {
+ if src == dst {
+ return OCONVNOP, ""
+ }
+ if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil {
+ return OXXX, ""
+ }
+
+ // 1. src type is identical to dst.
+ if types.Identical(src, dst) {
+ return OCONVNOP, ""
+ }
+
+ // 2. src and dst have identical underlying types
+ // and either src or dst is not a named type or
+ // both are empty interface types.
+ // For assignable but different non-empty interface types,
+ // we want to recompute the itab. Recomputing the itab ensures
+ // that itabs are unique (thus an interface with a compile-time
+ // type I has an itab with interface type I).
+ if types.Identical(src.Orig, dst.Orig) {
+ if src.IsEmptyInterface() {
+ // Conversion between two empty interfaces
+ // requires no code.
+ return OCONVNOP, ""
+ }
+ if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() {
+ // Conversion between two types, at least one unnamed,
+ // needs no conversion. The exception is nonempty interfaces
+ // which need to have their itab updated.
+ return OCONVNOP, ""
+ }
+ }
+
+ // 3. dst is an interface type and src implements dst.
+ if dst.IsInterface() && src.Etype != TNIL {
+ var missing, have *types.Field
+ var ptr int
+ if implements(src, dst, &missing, &have, &ptr) {
+ return OCONVIFACE, ""
+ }
+
+ // we'll have complained about this method anyway, suppress spurious messages.
+ if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
+ return OCONVIFACE, ""
+ }
+
+ var why string
+ if isptrto(src, TINTER) {
+ why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
+ } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
+ } else if have != nil && have.Sym == missing.Sym {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
+ "\t\thave %v%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%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)
+ }
+
+ return OXXX, why
+ }
+
+ if isptrto(dst, TINTER) {
+ why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
+ return OXXX, why
+ }
+
+ if src.IsInterface() && dst.Etype != TBLANK {
+ var missing, have *types.Field
+ var ptr int
+ var why string
+ if implements(dst, src, &missing, &have, &ptr) {
+ why = ": need type assertion"
+ }
+ return OXXX, why
+ }
+
+ // 4. src is a bidirectional channel value, dst is a channel type,
+ // src and dst have identical element types, and
+ // either src or dst is not a named type.
+ if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
+ if types.Identical(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
+ return OCONVNOP, ""
+ }
+ }
+
+ // 5. src is the predeclared identifier nil and dst is a nillable type.
+ if src.Etype == TNIL {
+ switch dst.Etype {
+ case TPTR,
+ TFUNC,
+ TMAP,
+ TCHAN,
+ TINTER,
+ TSLICE:
+ return OCONVNOP, ""
+ }
+ }
+
+ // 6. rule about untyped constants - already converted by defaultlit.
+
+ // 7. Any typed value can be assigned to the blank identifier.
+ if dst.Etype == TBLANK {
+ return OCONVNOP, ""
+ }
+
+ return OXXX, ""
+}
+
+// Can we convert a value of type src to a value of type dst?
+// If so, return op code to use in conversion (maybe OCONVNOP).
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
+// srcConstant indicates whether the value of type src is a constant.
+func convertop(srcConstant bool, src, dst *types.Type) (Op, string) {
+ if src == dst {
+ return OCONVNOP, ""
+ }
+ if src == nil || dst == nil {
+ return OXXX, ""
+ }
+
+ // Conversions from regular to go:notinheap are not allowed
+ // (unless it's unsafe.Pointer). These are runtime-specific
+ // rules.
+ // (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
+ if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
+ why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
+ return OXXX, why
+ }
+ // (b) Disallow string to []T where T is go:notinheap.
+ if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Etype == types.Bytetype.Etype || dst.Elem().Etype == types.Runetype.Etype) {
+ why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
+ return OXXX, why
+ }
+
+ // 1. src can be assigned to dst.
+ op, why := assignop(src, dst)
+ if op != OXXX {
+ return op, why
+ }
+
+ // The rules for interfaces are no different in conversions
+ // than assignments. If interfaces are involved, stop now
+ // with the good message from assignop.
+ // Otherwise clear the error.
+ if src.IsInterface() || dst.IsInterface() {
+ return OXXX, why
+ }
+
+ // 2. Ignoring struct tags, src and dst have identical underlying types.
+ if types.IdenticalIgnoreTags(src.Orig, dst.Orig) {
+ return OCONVNOP, ""
+ }
+
+ // 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 types.IdenticalIgnoreTags(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] {
+ return OCONVNOP, ""
+ }
+ return OCONV, ""
+ }
+
+ // 5. src and dst are both complex types.
+ if src.IsComplex() && dst.IsComplex() {
+ if simtype[src.Etype] == simtype[dst.Etype] {
+ return OCONVNOP, ""
+ }
+ return OCONV, ""
+ }
+
+ // Special case for constant conversions: any numeric
+ // conversion is potentially okay. We'll validate further
+ // within evconst. See #38117.
+ if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
+ return OCONV, ""
+ }
+
+ // 6. src is an integer or has type []byte or []rune
+ // and dst is a string type.
+ if src.IsInteger() && dst.IsString() {
+ return ORUNESTR, ""
+ }
+
+ if src.IsSlice() && dst.IsString() {
+ if src.Elem().Etype == types.Bytetype.Etype {
+ return OBYTES2STR, ""
+ }
+ if src.Elem().Etype == types.Runetype.Etype {
+ return ORUNES2STR, ""
+ }
+ }
+
+ // 7. src is a string and dst is []byte or []rune.
+ // String to slice.
+ if src.IsString() && dst.IsSlice() {
+ if dst.Elem().Etype == types.Bytetype.Etype {
+ return OSTR2BYTES, ""
+ }
+ if dst.Elem().Etype == types.Runetype.Etype {
+ return OSTR2RUNES, ""
+ }
+ }
+
+ // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
+ if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
+ return OCONVNOP, ""
+ }
+
+ // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
+ if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
+ return OCONVNOP, ""
+ }
+
+ // src is map and dst is a pointer to corresponding hmap.
+ // This rule is needed for the implementation detail that
+ // go gc maps are implemented as a pointer to a hmap struct.
+ if src.Etype == TMAP && dst.IsPtr() &&
+ src.MapType().Hmap == dst.Elem() {
+ return OCONVNOP, ""
+ }
+
+ return OXXX, ""
+}
+
+func assignconv(n *Node, t *types.Type, context string) *Node {
+ return assignconvfn(n, t, func() string { return context })
+}
+
+// Convert node n for assignment to type t.
+func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
+ if n == nil || n.Type == nil || n.Type.Broke() {
+ return n
+ }
+
+ if t.Etype == TBLANK && n.Type.Etype == TNIL {
+ yyerror("use of untyped nil")
+ }
+
+ n = convlit1(n, t, false, context)
+ if n.Type == nil {
+ return n
+ }
+ if t.Etype == TBLANK {
+ return n
+ }
+
+ // Convert ideal bool from comparison to plain bool
+ // if the next step is non-bool (like interface{}).
+ if n.Type == types.UntypedBool && !t.IsBoolean() {
+ if n.Op == ONAME || n.Op == OLITERAL {
+ r := nod(OCONVNOP, n, nil)
+ r.Type = types.Types[TBOOL]
+ r.SetTypecheck(1)
+ r.SetImplicit(true)
+ n = r
+ }
+ }
+
+ if types.Identical(n.Type, t) {
+ return n
+ }
+
+ op, why := assignop(n.Type, t)
+ if op == OXXX {
+ yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
+ op = OCONV
+ }
+
+ r := nod(op, n, nil)
+ r.Type = t
+ r.SetTypecheck(1)
+ r.SetImplicit(true)
+ r.Orig = n.Orig
+ return r
+}
+
+// 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:
+ s := n.List.Slice()
+ return s[0], s[1], nil
+ case OSLICE3, OSLICE3ARR:
+ s := n.List.Slice()
+ return s[0], s[1], s[2]
+ }
+ Fatalf("SliceBounds op %v: %v", n.Op, n)
+ return nil, nil, nil
+}
+
+// SetSliceBounds sets n's slice bounds, where n is a slice expression.
+// n must be a slice expression. If max is non-nil, n must be a full slice expression.
+func (n *Node) SetSliceBounds(low, high, max *Node) {
+ switch n.Op {
+ case OSLICE, OSLICEARR, OSLICESTR:
+ if max != nil {
+ Fatalf("SetSliceBounds %v given three bounds", n.Op)
+ }
+ s := n.List.Slice()
+ if s == nil {
+ if low == nil && high == nil {
+ return
+ }
+ n.List.Set2(low, high)
+ return
+ }
+ s[0] = low
+ s[1] = high
+ return
+ case OSLICE3, OSLICE3ARR:
+ s := n.List.Slice()
+ if s == nil {
+ if low == nil && high == nil && max == nil {
+ return
+ }
+ n.List.Set3(low, high, max)
+ return
+ }
+ s[0] = low
+ s[1] = high
+ s[2] = max
+ return
+ }
+ Fatalf("SetSliceBounds op %v: %v", n.Op, n)
+}
+
+// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
+// o must be a slicing op.
+func (o Op) IsSlice3() bool {
+ switch o {
+ case OSLICE, OSLICEARR, OSLICESTR:
+ return false
+ case OSLICE3, OSLICE3ARR:
+ return true
+ }
+ Fatalf("IsSlice3 op %v", o)
+ return false
+}
+
+// backingArrayPtrLen extracts the pointer and length from a slice or string.
+// This constructs two nodes referring to n, so n must be a cheapexpr.
+func (n *Node) backingArrayPtrLen() (ptr, len *Node) {
+ var init Nodes
+ c := cheapexpr(n, &init)
+ if c != n || init.Len() != 0 {
+ Fatalf("backingArrayPtrLen not cheap: %v", n)
+ }
+ ptr = nod(OSPTR, n, nil)
+ if n.Type.IsString() {
+ ptr.Type = types.Types[TUINT8].PtrTo()
+ } else {
+ ptr.Type = n.Type.Elem().PtrTo()
+ }
+ len = nod(OLEN, n, nil)
+ len.Type = types.Types[TINT]
+ return ptr, len
+}
+
+// labeledControl returns the control flow Node (for, switch, select)
+// associated with the label n, if any.
+func (n *Node) labeledControl() *Node {
+ if n.Op != OLABEL {
+ Fatalf("labeledControl %v", n.Op)
+ }
+ ctl := n.Name.Defn
+ if ctl == nil {
+ return nil
+ }
+ switch ctl.Op {
+ case OFOR, OFORUNTIL, OSWITCH, OSELECT:
+ return ctl
+ }
+ return nil
+}
+
+func syslook(name string) *Node {
+ s := Runtimepkg.Lookup(name)
+ if s == nil || s.Def == nil {
+ Fatalf("syslook: can't find runtime.%s", name)
+ }
+ return asNode(s.Def)
+}
+
+// typehash computes a hash value for type t to use in type switch statements.
+func typehash(t *types.Type) uint32 {
+ p := t.LongString()
+
+ // Using MD5 is overkill, but reduces accidental collisions.
+ h := md5.Sum([]byte(p))
+ return binary.LittleEndian.Uint32(h[:4])
+}
+
+// updateHasCall checks whether expression n contains any function
+// calls and sets the n.HasCall flag if so.
+func updateHasCall(n *Node) {
+ if n == nil {
+ return
+ }
+ n.SetHasCall(calcHasCall(n))
+}
+
+func calcHasCall(n *Node) bool {
+ if n.Ninit.Len() != 0 {
+ // TODO(mdempsky): This seems overly conservative.
+ return true
+ }
+
+ switch n.Op {
+ case OLITERAL, ONAME, OTYPE:
+ if n.HasCall() {
+ Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n)
+ }
+ return false
+ case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
+ return true
+ case OANDAND, OOROR:
+ // hard with instrumented code
+ if instrumenting {
+ return true
+ }
+ case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR,
+ ODEREF, ODOTPTR, ODOTTYPE, ODIV, OMOD:
+ // These ops might panic, make sure they are done
+ // before we start marshaling args for a call. See issue 16760.
+ return true
+
+ // When using soft-float, these ops might be rewritten to function calls
+ // so we ensure they are evaluated first.
+ case OADD, OSUB, ONEG, OMUL:
+ if thearch.SoftFloat && (isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) {
+ return true
+ }
+ case OLT, OEQ, ONE, OLE, OGE, OGT:
+ if thearch.SoftFloat && (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype]) {
+ return true
+ }
+ case OCONV:
+ if thearch.SoftFloat && ((isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) || (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype])) {
+ return true
+ }
+ }
+
+ if n.Left != nil && n.Left.HasCall() {
+ return true
+ }
+ if n.Right != nil && n.Right.HasCall() {
+ return true
+ }
+ return false
+}
+
+func badtype(op Op, tl, tr *types.Type) {
+ var s string
+ if tl != nil {
+ s += fmt.Sprintf("\n\t%v", tl)
+ }
+ if tr != nil {
+ s += fmt.Sprintf("\n\t%v", tr)
+ }
+
+ // common mistake: *struct and *interface.
+ if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
+ if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
+ s += "\n\t(*struct vs *interface)"
+ } else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
+ s += "\n\t(*interface vs *struct)"
+ }
+ }
+
+ yyerror("illegal types for operand: %v%s", op, s)
+}
+
+// brcom returns !(op).
+// For example, brcom(==) is !=.
+func brcom(op Op) Op {
+ switch op {
+ case OEQ:
+ return ONE
+ case ONE:
+ return OEQ
+ case OLT:
+ return OGE
+ case OGT:
+ return OLE
+ case OLE:
+ return OGT
+ case OGE:
+ return OLT
+ }
+ Fatalf("brcom: no com for %v\n", op)
+ return op
+}
+
+// brrev returns reverse(op).
+// For example, Brrev(<) is >.
+func brrev(op Op) Op {
+ switch op {
+ case OEQ:
+ return OEQ
+ case ONE:
+ return ONE
+ case OLT:
+ return OGT
+ case OGT:
+ return OLT
+ case OLE:
+ return OGE
+ case OGE:
+ return OLE
+ }
+ Fatalf("brrev: no rev for %v\n", op)
+ return op
+}
+
+// return side effect-free n, appending side effects to init.
+// result is assignable if n is.
+func safeexpr(n *Node, init *Nodes) *Node {
+ if n == nil {
+ return nil
+ }
+
+ if n.Ninit.Len() != 0 {
+ walkstmtlist(n.Ninit.Slice())
+ init.AppendNodes(&n.Ninit)
+ }
+
+ switch n.Op {
+ case ONAME, OLITERAL:
+ return n
+
+ case ODOT, OLEN, OCAP:
+ l := safeexpr(n.Left, init)
+ if l == n.Left {
+ return n
+ }
+ r := n.copy()
+ r.Left = l
+ r = typecheck(r, ctxExpr)
+ r = walkexpr(r, init)
+ return r
+
+ case ODOTPTR, ODEREF:
+ l := safeexpr(n.Left, init)
+ if l == n.Left {
+ return n
+ }
+ a := n.copy()
+ a.Left = l
+ a = walkexpr(a, init)
+ return a
+
+ case OINDEX, OINDEXMAP:
+ l := safeexpr(n.Left, init)
+ r := safeexpr(n.Right, init)
+ if l == n.Left && r == n.Right {
+ return n
+ }
+ a := n.copy()
+ a.Left = l
+ a.Right = r
+ a = walkexpr(a, init)
+ return a
+
+ case OSTRUCTLIT, OARRAYLIT, OSLICELIT:
+ if isStaticCompositeLiteral(n) {
+ return n
+ }
+ }
+
+ // make a copy; must not be used as an lvalue
+ if islvalue(n) {
+ Fatalf("missing lvalue case in safeexpr: %v", n)
+ }
+ return cheapexpr(n, init)
+}
+
+func copyexpr(n *Node, t *types.Type, init *Nodes) *Node {
+ l := temp(t)
+ a := nod(OAS, l, n)
+ a = typecheck(a, ctxStmt)
+ a = walkexpr(a, init)
+ init.Append(a)
+ return l
+}
+
+// return side-effect free and cheap n, appending side effects to init.
+// result may not be assignable.
+func cheapexpr(n *Node, init *Nodes) *Node {
+ switch n.Op {
+ case ONAME, OLITERAL:
+ return n
+ }
+
+ return copyexpr(n, n.Type, init)
+}
+
+// Code to resolve elided DOTs in embedded types.
+
+// A Dlist stores a pointer to a TFIELD Type embedded within
+// a TSTRUCT or TINTER Type.
+type Dlist struct {
+ field *types.Field
+}
+
+// dotlist is used by adddot1 to record the path of embedded fields
+// used to access a target field or method.
+// Must be non-nil so that dotpath returns a non-nil slice even if d is zero.
+var dotlist = make([]Dlist, 10)
+
+// lookdot0 returns the number of fields or methods named s associated
+// with Type t. If exactly one exists, it will be returned in *save
+// (if save is not nil).
+func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
+ u := t
+ if u.IsPtr() {
+ u = u.Elem()
+ }
+
+ c := 0
+ if u.IsStruct() || u.IsInterface() {
+ for _, f := range u.Fields().Slice() {
+ if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
+ if save != nil {
+ *save = f
+ }
+ c++
+ }
+ }
+ }
+
+ u = t
+ if t.Sym != nil && t.IsPtr() && !t.Elem().IsPtr() {
+ // If t is a defined pointer type, then x.m is shorthand for (*x).m.
+ u = t.Elem()
+ }
+ u = methtype(u)
+ if u != nil {
+ for _, f := range u.Methods().Slice() {
+ if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
+ if save != nil {
+ *save = f
+ }
+ c++
+ }
+ }
+ }
+
+ return c
+}
+
+// adddot1 returns the number of fields or methods named s at depth d in Type t.
+// If exactly one exists, it will be returned in *save (if save is not nil),
+// and dotlist will contain the path of embedded fields traversed to find it,
+// in reverse order. If none exist, more will indicate whether t contains any
+// embedded fields at depth d, so callers can decide whether to retry at
+// a greater depth.
+func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
+ if t.Recur() {
+ return
+ }
+ t.SetRecur(true)
+ defer t.SetRecur(false)
+
+ var u *types.Type
+ d--
+ if d < 0 {
+ // We've reached our target depth. If t has any fields/methods
+ // named s, then we're done. Otherwise, we still need to check
+ // below for embedded fields.
+ c = lookdot0(s, t, save, ignorecase)
+ if c != 0 {
+ return c, false
+ }
+ }
+
+ u = t
+ if u.IsPtr() {
+ u = u.Elem()
+ }
+ if !u.IsStruct() && !u.IsInterface() {
+ return c, false
+ }
+
+ for _, f := range u.Fields().Slice() {
+ if f.Embedded == 0 || f.Sym == nil {
+ continue
+ }
+ if d < 0 {
+ // Found an embedded field at target depth.
+ return c, true
+ }
+ a, more1 := adddot1(s, f.Type, d, save, ignorecase)
+ if a != 0 && c == 0 {
+ dotlist[d].field = f
+ }
+ c += a
+ if more1 {
+ more = true
+ }
+ }
+
+ return c, more
+}
+
+// dotpath computes the unique shortest explicit selector path to fully qualify
+// a selection expression x.f, where x is of type t and f is the symbol s.
+// If no such path exists, dotpath returns nil.
+// If there are multiple shortest paths to the same depth, ambig is true.
+func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []Dlist, ambig bool) {
+ // The embedding of types within structs imposes a tree structure onto
+ // types: structs parent the types they embed, and types parent their
+ // fields or methods. Our goal here is to find the shortest path to
+ // a field or method named s in the subtree rooted at t. To accomplish
+ // that, we iteratively perform depth-first searches of increasing depth
+ // until we either find the named field/method or exhaust the tree.
+ for d := 0; ; d++ {
+ if d > len(dotlist) {
+ dotlist = append(dotlist, Dlist{})
+ }
+ if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
+ return dotlist[:d], false
+ } else if c > 1 {
+ return nil, true
+ } else if !more {
+ return nil, false
+ }
+ }
+}
+
+// in T.field
+// find missing fields that
+// will give shortest unique addressing.
+// modify the tree with missing type names.
+func adddot(n *Node) *Node {
+ n.Left = typecheck(n.Left, ctxType|ctxExpr)
+ if n.Left.Diag() {
+ n.SetDiag(true)
+ }
+ t := n.Left.Type
+ if t == nil {
+ return n
+ }
+
+ if n.Left.Op == OTYPE {
+ return n
+ }
+
+ s := n.Sym
+ if s == nil {
+ return n
+ }
+
+ switch path, ambig := dotpath(s, t, nil, false); {
+ case path != nil:
+ // rebuild elided dots
+ for c := len(path) - 1; c >= 0; c-- {
+ n.Left = nodSym(ODOT, n.Left, path[c].field.Sym)
+ n.Left.SetImplicit(true)
+ }
+ case ambig:
+ yyerror("ambiguous selector %v", n)
+ n.Left = nil
+ }
+
+ return n
+}
+
+// Code to help generate trampoline functions for methods on embedded
+// types. These are approx the same as the corresponding adddot
+// routines except that they expect to be called with unique tasks and
+// they return the actual methods.
+
+type Symlink struct {
+ field *types.Field
+}
+
+var slist []Symlink
+
+func expand0(t *types.Type) {
+ u := t
+ if u.IsPtr() {
+ u = u.Elem()
+ }
+
+ if u.IsInterface() {
+ for _, f := range u.Fields().Slice() {
+ if f.Sym.Uniq() {
+ continue
+ }
+ f.Sym.SetUniq(true)
+ slist = append(slist, Symlink{field: f})
+ }
+
+ return
+ }
+
+ u = methtype(t)
+ if u != nil {
+ for _, f := range u.Methods().Slice() {
+ if f.Sym.Uniq() {
+ continue
+ }
+ f.Sym.SetUniq(true)
+ slist = append(slist, Symlink{field: f})
+ }
+ }
+}
+
+func expand1(t *types.Type, top bool) {
+ if t.Recur() {
+ return
+ }
+ t.SetRecur(true)
+
+ if !top {
+ expand0(t)
+ }
+
+ u := t
+ if u.IsPtr() {
+ u = u.Elem()
+ }
+
+ if u.IsStruct() || u.IsInterface() {
+ for _, f := range u.Fields().Slice() {
+ if f.Embedded == 0 {
+ continue
+ }
+ if f.Sym == nil {
+ continue
+ }
+ expand1(f.Type, false)
+ }
+ }
+
+ t.SetRecur(false)
+}
+
+func expandmeth(t *types.Type) {
+ if t == nil || t.AllMethods().Len() != 0 {
+ return
+ }
+
+ // mark top-level method symbols
+ // so that expand1 doesn't consider them.
+ for _, f := range t.Methods().Slice() {
+ f.Sym.SetUniq(true)
+ }
+
+ // generate all reachable methods
+ slist = slist[:0]
+ expand1(t, true)
+
+ // check each method to be uniquely reachable
+ var ms []*types.Field
+ for i, sl := range slist {
+ slist[i].field = nil
+ sl.field.Sym.SetUniq(false)
+
+ var f *types.Field
+ path, _ := dotpath(sl.field.Sym, t, &f, false)
+ if path == nil {
+ continue
+ }
+
+ // dotpath may have dug out arbitrary fields, we only want methods.
+ if !f.IsMethod() {
+ continue
+ }
+
+ // add it to the base type method list
+ f = f.Copy()
+ f.Embedded = 1 // needs a trampoline
+ for _, d := range path {
+ if d.field.Type.IsPtr() {
+ f.Embedded = 2
+ break
+ }
+ }
+ ms = append(ms, f)
+ }
+
+ for _, f := range t.Methods().Slice() {
+ f.Sym.SetUniq(false)
+ }
+
+ ms = append(ms, t.Methods().Slice()...)
+ sort.Sort(methcmp(ms))
+ t.AllMethods().Set(ms)
+}
+
+// Given funarg struct list, return list of ODCLFIELD Node fn args.
+func structargs(tl *types.Type, mustname bool) []*Node {
+ var args []*Node
+ gen := 0
+ for _, t := range tl.Fields().Slice() {
+ s := t.Sym
+ if mustname && (s == nil || s.Name == "_") {
+ // invent a name so that we can refer to it in the trampoline
+ s = lookupN(".anon", gen)
+ gen++
+ }
+ a := symfield(s, t.Type)
+ a.Pos = t.Pos
+ a.SetIsDDD(t.IsDDD())
+ args = append(args, a)
+ }
+
+ return args
+}
+
+// Generate a wrapper function to convert from
+// a receiver of type T to a receiver of type U.
+// That is,
+//
+// func (t T) M() {
+// ...
+// }
+//
+// already exists; this function generates
+//
+// func (u U) M() {
+// u.M()
+// }
+//
+// where the types T and U are such that u.M() is valid
+// and calls the T.M method.
+// The resulting function is for use in method tables.
+//
+// rcvr - U
+// method - M func (t T)(), a TFIELD type struct
+// newnam - the eventual mangled name of this function
+func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
+ if false && Debug.r != 0 {
+ fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
+ }
+
+ // Only generate (*T).M wrappers for T.M in T's own package.
+ if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
+ rcvr.Elem().Sym != nil && rcvr.Elem().Sym.Pkg != localpkg {
+ return
+ }
+
+ // Only generate I.M wrappers for I in I's own package
+ // but keep doing it for error.Error (was issue #29304).
+ if rcvr.IsInterface() && rcvr.Sym != nil && rcvr.Sym.Pkg != localpkg && rcvr != types.Errortype {
+ return
+ }
+
+ lineno = autogeneratedPos
+ dclcontext = PEXTERN
+
+ tfn := nod(OTFUNC, nil, nil)
+ tfn.Left = namedfield(".this", rcvr)
+ tfn.List.Set(structargs(method.Type.Params(), true))
+ tfn.Rlist.Set(structargs(method.Type.Results(), false))
+
+ fn := dclfunc(newnam, tfn)
+ fn.Func.SetDupok(true)
+
+ nthis := asNode(tfn.Type.Recv().Nname)
+
+ methodrcvr := method.Type.Recv().Type
+
+ // 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.Left = nod(OEQ, nthis, nodnil())
+ call := nod(OCALL, syslook("panicwrap"), nil)
+ n.Nbody.Set1(call)
+ fn.Nbody.Append(n)
+ }
+
+ dot := adddot(nodSym(OXDOT, nthis, method.Sym))
+
+ // generate call
+ // It's not possible to use a tail call when dynamic linking on ppc64le. The
+ // bad scenario is when a local call is made to the wrapper: the wrapper will
+ // call the implementation, which might be in a different module and so set
+ // the TOC to the appropriate value for that module. But if it returns
+ // directly to the wrapper's caller, nothing will reset it to the correct
+ // value for that function.
+ if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(thearch.LinkArch.Name == "ppc64le" && Ctxt.Flag_dynlink) {
+ // generate tail call: adjust pointer receiver and jump to embedded method.
+ dot = dot.Left // skip final .M
+ // TODO(mdempsky): Remove dependency on dotlist.
+ if !dotlist[0].field.Type.IsPtr() {
+ dot = nod(OADDR, dot, nil)
+ }
+ as := nod(OAS, nthis, convnop(dot, rcvr))
+ fn.Nbody.Append(as)
+ fn.Nbody.Append(nodSym(ORETJMP, nil, methodSym(methodrcvr, method.Sym)))
+ } else {
+ fn.Func.SetWrapper(true) // ignore frame for panic+recover matching
+ call := nod(OCALL, dot, nil)
+ call.List.Set(paramNnames(tfn.Type))
+ call.SetIsDDD(tfn.Type.IsVariadic())
+ if method.Type.NumResults() > 0 {
+ n := nod(ORETURN, nil, nil)
+ n.List.Set1(call)
+ call = n
+ }
+ fn.Nbody.Append(call)
+ }
+
+ if false && Debug.r != 0 {
+ dumplist("genwrapper body", fn.Nbody)
+ }
+
+ funcbody()
+ if debug_dclstack != 0 {
+ testdclstack()
+ }
+
+ fn = typecheck(fn, ctxStmt)
+
+ Curfn = fn
+ typecheckslice(fn.Nbody.Slice(), ctxStmt)
+
+ // Inline calls within (*T).M wrappers. This is safe because we only
+ // generate those wrappers within the same compilation unit as (T).M.
+ // TODO(mdempsky): Investigate why we can't enable this more generally.
+ if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil {
+ inlcalls(fn)
+ }
+ escapeFuncs([]*Node{fn}, false)
+
+ Curfn = nil
+ xtop = append(xtop, fn)
+}
+
+func paramNnames(ft *types.Type) []*Node {
+ args := make([]*Node, ft.NumParams())
+ for i, f := range ft.Params().FieldSlice() {
+ args[i] = asNode(f.Nname)
+ }
+ return args
+}
+
+func hashmem(t *types.Type) *Node {
+ sym := Runtimepkg.Lookup("memhash")
+
+ n := newname(sym)
+ setNodeNameFunc(n)
+ n.Type = functype(nil, []*Node{
+ anonfield(types.NewPtr(t)),
+ anonfield(types.Types[TUINTPTR]),
+ anonfield(types.Types[TUINTPTR]),
+ }, []*Node{
+ anonfield(types.Types[TUINTPTR]),
+ })
+ return n
+}
+
+func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, followptr bool) {
+ if t == nil {
+ return nil, false
+ }
+
+ path, ambig := dotpath(s, t, &m, ignorecase)
+ if path == nil {
+ if ambig {
+ yyerror("%v.%v is ambiguous", t, s)
+ }
+ return nil, false
+ }
+
+ for _, d := range path {
+ if d.field.Type.IsPtr() {
+ followptr = true
+ break
+ }
+ }
+
+ if !m.IsMethod() {
+ yyerror("%v.%v is a field, not a method", t, s)
+ return nil, followptr
+ }
+
+ return m, followptr
+}
+
+func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
+ t0 := t
+ if t == nil {
+ return false
+ }
+
+ if t.IsInterface() {
+ i := 0
+ tms := t.Fields().Slice()
+ for _, im := range iface.Fields().Slice() {
+ for i < len(tms) && tms[i].Sym != im.Sym {
+ i++
+ }
+ if i == len(tms) {
+ *m = im
+ *samename = nil
+ *ptr = 0
+ return false
+ }
+ tm := tms[i]
+ if !types.Identical(tm.Type, im.Type) {
+ *m = im
+ *samename = tm
+ *ptr = 0
+ return false
+ }
+ }
+
+ return true
+ }
+
+ t = methtype(t)
+ var tms []*types.Field
+ if t != nil {
+ expandmeth(t)
+ tms = t.AllMethods().Slice()
+ }
+ i := 0
+ for _, im := range iface.Fields().Slice() {
+ if im.Broke() {
+ continue
+ }
+ for i < len(tms) && tms[i].Sym != im.Sym {
+ i++
+ }
+ if i == len(tms) {
+ *m = im
+ *samename, _ = ifacelookdot(im.Sym, t, true)
+ *ptr = 0
+ return false
+ }
+ tm := tms[i]
+ if tm.Nointerface() || !types.Identical(tm.Type, im.Type) {
+ *m = im
+ *samename = tm
+ *ptr = 0
+ return false
+ }
+ followptr := tm.Embedded == 2
+
+ // if pointer receiver in method,
+ // the method does not exist for value types.
+ rcvr := tm.Type.Recv().Type
+ if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
+ if false && Debug.r != 0 {
+ yyerror("interface pointer mismatch")
+ }
+
+ *m = im
+ *samename = nil
+ *ptr = 1
+ return false
+ }
+ }
+
+ // We're going to emit an OCONVIFACE.
+ // Call itabname so that (t, iface)
+ // gets added to itabs early, which allows
+ // us to de-virtualize calls through this
+ // type/interface pair later. See peekitabs in reflect.go
+ if isdirectiface(t0) && !iface.IsEmptyInterface() {
+ itabname(t0, iface)
+ }
+ return true
+}
+
+func listtreecopy(l []*Node, pos src.XPos) []*Node {
+ var out []*Node
+ for _, n := range l {
+ out = append(out, treecopy(n, pos))
+ }
+ return out
+}
+
+func liststmt(l []*Node) *Node {
+ n := nod(OBLOCK, nil, nil)
+ n.List.Set(l)
+ if len(l) != 0 {
+ n.Pos = l[0].Pos
+ }
+ return n
+}
+
+func (l Nodes) asblock() *Node {
+ n := nod(OBLOCK, nil, nil)
+ n.List = l
+ if l.Len() != 0 {
+ n.Pos = l.First().Pos
+ }
+ return n
+}
+
+func ngotype(n *Node) *types.Sym {
+ if n.Type != nil {
+ return typenamesym(n.Type)
+ }
+ return nil
+}
+
+// The result of addinit MUST be assigned back to n, e.g.
+// n.Left = addinit(n.Left, init)
+func addinit(n *Node, init []*Node) *Node {
+ if len(init) == 0 {
+ return n
+ }
+ if n.mayBeShared() {
+ // Introduce OCONVNOP to hold init list.
+ n = nod(OCONVNOP, n, nil)
+ n.Type = n.Left.Type
+ n.SetTypecheck(1)
+ }
+
+ n.Ninit.Prepend(init...)
+ n.SetHasCall(true)
+ return n
+}
+
+// The linker uses the magic symbol prefixes "go." and "type."
+// Avoid potential confusion between import paths and symbols
+// by rejecting these reserved imports for now. Also, people
+// "can do weird things in GOPATH and we'd prefer they didn't
+// do _that_ weird thing" (per rsc). See also #4257.
+var reservedimports = []string{
+ "go",
+ "type",
+}
+
+func isbadimport(path string, allowSpace bool) bool {
+ if strings.Contains(path, "\x00") {
+ 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)
+ return true
+ }
+ }
+
+ for _, r := range path {
+ if r == utf8.RuneError {
+ yyerror("import path contains invalid UTF-8 sequence: %q", path)
+ return true
+ }
+
+ if r < 0x20 || r == 0x7f {
+ yyerror("import path contains control character: %q", path)
+ return true
+ }
+
+ if r == '\\' {
+ yyerror("import path contains backslash; use slash: %q", path)
+ return true
+ }
+
+ if !allowSpace && unicode.IsSpace(r) {
+ yyerror("import path contains space character: %q", path)
+ return true
+ }
+
+ if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) {
+ yyerror("import path contains invalid character '%c': %q", r, path)
+ return true
+ }
+ }
+
+ return false
+}
+
+// Can this type be stored directly in an interface word?
+// Yes, if the representation is a single pointer.
+func isdirectiface(t *types.Type) bool {
+ if t.Broke() {
+ return false
+ }
+
+ switch t.Etype {
+ case TPTR:
+ // Pointers to notinheap types must be stored indirectly. See issue 42076.
+ return !t.Elem().NotInHeap()
+ case TCHAN,
+ TMAP,
+ TFUNC,
+ TUNSAFEPTR:
+ return true
+
+ case TARRAY:
+ // Array of 1 direct iface type can be direct.
+ return t.NumElem() == 1 && isdirectiface(t.Elem())
+
+ case TSTRUCT:
+ // Struct with 1 field of direct iface type can be direct.
+ return t.NumFields() == 1 && isdirectiface(t.Field(0).Type)
+ }
+
+ return false
+}
+
+// itabType loads the _type field from a runtime.itab struct.
+func itabType(itab *Node) *Node {
+ typ := nodSym(ODOTPTR, itab, nil)
+ typ.Type = types.NewPtr(types.Types[TUINT8])
+ typ.SetTypecheck(1)
+ typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
+ typ.SetBounded(true) // guaranteed not to fault
+ return typ
+}
+
+// ifaceData loads the data field from an interface.
+// The concrete type must be known to have type t.
+// It follows the pointer if !isdirectiface(t).
+func ifaceData(pos src.XPos, n *Node, t *types.Type) *Node {
+ if t.IsInterface() {
+ Fatalf("ifaceData interface: %v", t)
+ }
+ ptr := nodlSym(pos, OIDATA, n, nil)
+ if isdirectiface(t) {
+ ptr.Type = t
+ ptr.SetTypecheck(1)
+ return ptr
+ }
+ ptr.Type = types.NewPtr(t)
+ ptr.SetTypecheck(1)
+ ind := nodl(pos, ODEREF, ptr, nil)
+ ind.Type = t
+ ind.SetTypecheck(1)
+ ind.SetBounded(true)
+ return ind
+}
+
+// typePos returns the position associated with t.
+// This is where t was declared or where it appeared as a type expression.
+func typePos(t *types.Type) src.XPos {
+ n := asNode(t.Nod)
+ if n == nil || !n.Pos.IsKnown() {
+ Fatalf("bad type: %v", t)
+ }
+ return n.Pos
+}
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
new file mode 100644
index 0000000..8d9fbe3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -0,0 +1,756 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "sort"
+)
+
+// typecheckswitch typechecks a switch statement.
+func typecheckswitch(n *Node) {
+ typecheckslice(n.Ninit.Slice(), ctxStmt)
+ if n.Left != nil && n.Left.Op == OTYPESW {
+ typecheckTypeSwitch(n)
+ } else {
+ typecheckExprSwitch(n)
+ }
+}
+
+func typecheckTypeSwitch(n *Node) {
+ n.Left.Right = typecheck(n.Left.Right, ctxExpr)
+ t := n.Left.Right.Type
+ if t != nil && !t.IsInterface() {
+ yyerrorl(n.Pos, "cannot type switch on non-interface value %L", n.Left.Right)
+ t = nil
+ }
+
+ // We don't actually declare the type switch's guarded
+ // declaration itself. So if there are no cases, we won't
+ // notice that it went unused.
+ if v := n.Left.Left; v != nil && !v.isBlank() && n.List.Len() == 0 {
+ yyerrorl(v.Pos, "%v declared but not used", v.Sym)
+ }
+
+ var defCase, nilCase *Node
+ var ts typeSet
+ for _, ncase := range n.List.Slice() {
+ ls := ncase.List.Slice()
+ if len(ls) == 0 { // default:
+ if defCase != nil {
+ yyerrorl(ncase.Pos, "multiple defaults in switch (first at %v)", defCase.Line())
+ } else {
+ defCase = ncase
+ }
+ }
+
+ for i := range ls {
+ ls[i] = typecheck(ls[i], ctxExpr|ctxType)
+ n1 := ls[i]
+ if t == nil || n1.Type == nil {
+ continue
+ }
+
+ var missing, have *types.Field
+ var ptr int
+ switch {
+ case n1.isNil(): // case nil:
+ if nilCase != nil {
+ yyerrorl(ncase.Pos, "multiple nil cases in type switch (first at %v)", nilCase.Line())
+ } else {
+ nilCase = ncase
+ }
+ case n1.Op != OTYPE:
+ yyerrorl(ncase.Pos, "%L is not a type", n1)
+ case !n1.Type.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr) && !missing.Broke():
+ if have != nil && !have.Broke() {
+ yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+
+ " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", n.Left.Right, n1.Type, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else if ptr != 0 {
+ yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+
+ " (%v method has pointer receiver)", n.Left.Right, n1.Type, missing.Sym)
+ } else {
+ yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+
+ " (missing %v method)", n.Left.Right, n1.Type, missing.Sym)
+ }
+ }
+
+ if n1.Op == OTYPE {
+ ts.add(ncase.Pos, n1.Type)
+ }
+ }
+
+ if ncase.Rlist.Len() != 0 {
+ // Assign the clause variable's type.
+ vt := t
+ if len(ls) == 1 {
+ if ls[0].Op == OTYPE {
+ vt = ls[0].Type
+ } else if ls[0].Op != OLITERAL { // TODO(mdempsky): Should be !ls[0].isNil()
+ // Invalid single-type case;
+ // mark variable as broken.
+ vt = nil
+ }
+ }
+
+ // TODO(mdempsky): It should be possible to
+ // still typecheck the case body.
+ if vt == nil {
+ continue
+ }
+
+ nvar := ncase.Rlist.First()
+ nvar.Type = vt
+ nvar = typecheck(nvar, ctxExpr|ctxAssign)
+ ncase.Rlist.SetFirst(nvar)
+ }
+
+ typecheckslice(ncase.Nbody.Slice(), ctxStmt)
+ }
+}
+
+type typeSet struct {
+ m map[string][]typeSetEntry
+}
+
+type typeSetEntry struct {
+ pos src.XPos
+ typ *types.Type
+}
+
+func (s *typeSet) add(pos src.XPos, typ *types.Type) {
+ if s.m == nil {
+ s.m = make(map[string][]typeSetEntry)
+ }
+
+ // LongString does not uniquely identify types, so we need to
+ // disambiguate collisions with types.Identical.
+ // TODO(mdempsky): Add a method that *is* unique.
+ ls := typ.LongString()
+ prevs := s.m[ls]
+ for _, prev := range prevs {
+ if types.Identical(typ, prev.typ) {
+ yyerrorl(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, linestr(prev.pos))
+ return
+ }
+ }
+ s.m[ls] = append(prevs, typeSetEntry{pos, typ})
+}
+
+func typecheckExprSwitch(n *Node) {
+ t := types.Types[TBOOL]
+ if n.Left != nil {
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ t = n.Left.Type
+ }
+
+ var nilonly string
+ if t != nil {
+ switch {
+ case t.IsMap():
+ nilonly = "map"
+ case t.Etype == TFUNC:
+ nilonly = "func"
+ case t.IsSlice():
+ nilonly = "slice"
+
+ case !IsComparable(t):
+ if t.IsStruct() {
+ yyerrorl(n.Pos, "cannot switch on %L (struct containing %v cannot be compared)", n.Left, IncomparableField(t).Type)
+ } else {
+ yyerrorl(n.Pos, "cannot switch on %L", n.Left)
+ }
+ t = nil
+ }
+ }
+
+ var defCase *Node
+ var cs constSet
+ for _, ncase := range n.List.Slice() {
+ ls := ncase.List.Slice()
+ if len(ls) == 0 { // default:
+ if defCase != nil {
+ yyerrorl(ncase.Pos, "multiple defaults in switch (first at %v)", defCase.Line())
+ } else {
+ defCase = ncase
+ }
+ }
+
+ for i := range ls {
+ setlineno(ncase)
+ ls[i] = typecheck(ls[i], ctxExpr)
+ ls[i] = defaultlit(ls[i], t)
+ n1 := ls[i]
+ if t == nil || n1.Type == nil {
+ continue
+ }
+
+ if nilonly != "" && !n1.isNil() {
+ yyerrorl(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
+ } else if t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type) {
+ yyerrorl(ncase.Pos, "invalid case %L in switch (incomparable type)", n1)
+ } else {
+ op1, _ := assignop(n1.Type, t)
+ op2, _ := assignop(t, n1.Type)
+ if op1 == OXXX && op2 == OXXX {
+ if n.Left != nil {
+ yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
+ } else {
+ yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
+ }
+ }
+ }
+
+ // 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 !n1.Type.IsBoolean() {
+ cs.add(ncase.Pos, n1, "case", "switch")
+ }
+ }
+
+ typecheckslice(ncase.Nbody.Slice(), ctxStmt)
+ }
+}
+
+// walkswitch walks a switch statement.
+func walkswitch(sw *Node) {
+ // Guard against double walk, see #25776.
+ if sw.List.Len() == 0 && sw.Nbody.Len() > 0 {
+ return // Was fatal, but eliminating every possible source of double-walking is hard
+ }
+
+ if sw.Left != nil && sw.Left.Op == OTYPESW {
+ walkTypeSwitch(sw)
+ } else {
+ walkExprSwitch(sw)
+ }
+}
+
+// walkExprSwitch generates an AST implementing sw. sw is an
+// expression switch.
+func walkExprSwitch(sw *Node) {
+ lno := setlineno(sw)
+
+ cond := sw.Left
+ sw.Left = nil
+
+ // convert switch {...} to switch true {...}
+ if cond == nil {
+ cond = nodbool(true)
+ cond = typecheck(cond, ctxExpr)
+ cond = defaultlit(cond, nil)
+ }
+
+ // Given "switch string(byteslice)",
+ // with all cases being side-effect free,
+ // use a zero-cost alias of the byte slice.
+ // Do this before calling walkexpr on cond,
+ // because walkexpr will lower the string
+ // conversion into a runtime call.
+ // See issue 24937 for more discussion.
+ if cond.Op == OBYTES2STR && allCaseExprsAreSideEffectFree(sw) {
+ cond.Op = OBYTES2STRTMP
+ }
+
+ cond = walkexpr(cond, &sw.Ninit)
+ if cond.Op != OLITERAL {
+ cond = copyexpr(cond, cond.Type, &sw.Nbody)
+ }
+
+ lineno = lno
+
+ s := exprSwitch{
+ exprname: cond,
+ }
+
+ var defaultGoto *Node
+ var body Nodes
+ for _, ncase := range sw.List.Slice() {
+ label := autolabel(".s")
+ jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label))
+
+ // Process case dispatch.
+ if ncase.List.Len() == 0 {
+ if defaultGoto != nil {
+ Fatalf("duplicate default case not detected during typechecking")
+ }
+ defaultGoto = jmp
+ }
+
+ for _, n1 := range ncase.List.Slice() {
+ s.Add(ncase.Pos, n1, jmp)
+ }
+
+ // Process body.
+ body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label)))
+ body.Append(ncase.Nbody.Slice()...)
+ if fall, pos := hasFall(ncase.Nbody.Slice()); !fall {
+ br := nod(OBREAK, nil, nil)
+ br.Pos = pos
+ body.Append(br)
+ }
+ }
+ sw.List.Set(nil)
+
+ if defaultGoto == nil {
+ br := nod(OBREAK, nil, nil)
+ br.Pos = br.Pos.WithNotStmt()
+ defaultGoto = br
+ }
+
+ s.Emit(&sw.Nbody)
+ sw.Nbody.Append(defaultGoto)
+ sw.Nbody.AppendNodes(&body)
+ walkstmtlist(sw.Nbody.Slice())
+}
+
+// An exprSwitch walks an expression switch.
+type exprSwitch struct {
+ exprname *Node // value being switched on
+
+ done Nodes
+ clauses []exprClause
+}
+
+type exprClause struct {
+ pos src.XPos
+ lo, hi *Node
+ jmp *Node
+}
+
+func (s *exprSwitch) Add(pos src.XPos, expr, jmp *Node) {
+ c := exprClause{pos: pos, lo: expr, hi: expr, jmp: jmp}
+ if okforcmp[s.exprname.Type.Etype] && expr.Op == OLITERAL {
+ s.clauses = append(s.clauses, c)
+ return
+ }
+
+ s.flush()
+ s.clauses = append(s.clauses, c)
+ s.flush()
+}
+
+func (s *exprSwitch) Emit(out *Nodes) {
+ s.flush()
+ out.AppendNodes(&s.done)
+}
+
+func (s *exprSwitch) flush() {
+ cc := s.clauses
+ s.clauses = nil
+ if len(cc) == 0 {
+ return
+ }
+
+ // Caution: If len(cc) == 1, then cc[0] might not an OLITERAL.
+ // The code below is structured to implicitly handle this case
+ // (e.g., sort.Slice doesn't need to invoke the less function
+ // when there's only a single slice element).
+
+ if s.exprname.Type.IsString() && len(cc) >= 2 {
+ // 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 below.
+ sort.Slice(cc, func(i, j int) bool {
+ si := cc[i].lo.StringVal()
+ sj := cc[j].lo.StringVal()
+ if len(si) != len(sj) {
+ return len(si) < len(sj)
+ }
+ return si < sj
+ })
+
+ // runLen returns the string length associated with a
+ // particular run of exprClauses.
+ runLen := func(run []exprClause) int64 { return int64(len(run[0].lo.StringVal())) }
+
+ // Collapse runs of consecutive strings with the same length.
+ var runs [][]exprClause
+ start := 0
+ for i := 1; i < len(cc); i++ {
+ if runLen(cc[start:]) != runLen(cc[i:]) {
+ runs = append(runs, cc[start:i])
+ start = i
+ }
+ }
+ runs = append(runs, cc[start:])
+
+ // Perform two-level binary search.
+ nlen := nod(OLEN, s.exprname, nil)
+ binarySearch(len(runs), &s.done,
+ func(i int) *Node {
+ return nod(OLE, nlen, nodintconst(runLen(runs[i-1])))
+ },
+ func(i int, nif *Node) {
+ run := runs[i]
+ nif.Left = nod(OEQ, nlen, nodintconst(runLen(run)))
+ s.search(run, &nif.Nbody)
+ },
+ )
+ return
+ }
+
+ sort.Slice(cc, func(i, j int) bool {
+ return compareOp(cc[i].lo.Val(), OLT, cc[j].lo.Val())
+ })
+
+ // Merge consecutive integer cases.
+ if s.exprname.Type.IsInteger() {
+ merged := cc[:1]
+ for _, c := range cc[1:] {
+ last := &merged[len(merged)-1]
+ if last.jmp == c.jmp && last.hi.Int64Val()+1 == c.lo.Int64Val() {
+ last.hi = c.lo
+ } else {
+ merged = append(merged, c)
+ }
+ }
+ cc = merged
+ }
+
+ s.search(cc, &s.done)
+}
+
+func (s *exprSwitch) search(cc []exprClause, out *Nodes) {
+ binarySearch(len(cc), out,
+ func(i int) *Node {
+ return nod(OLE, s.exprname, cc[i-1].hi)
+ },
+ func(i int, nif *Node) {
+ c := &cc[i]
+ nif.Left = c.test(s.exprname)
+ nif.Nbody.Set1(c.jmp)
+ },
+ )
+}
+
+func (c *exprClause) test(exprname *Node) *Node {
+ // Integer range.
+ if c.hi != c.lo {
+ low := nodl(c.pos, OGE, exprname, c.lo)
+ high := nodl(c.pos, OLE, exprname, c.hi)
+ return nodl(c.pos, OANDAND, low, high)
+ }
+
+ // Optimize "switch true { ...}" and "switch false { ... }".
+ if Isconst(exprname, CTBOOL) && !c.lo.Type.IsInterface() {
+ if exprname.BoolVal() {
+ return c.lo
+ } else {
+ return nodl(c.pos, ONOT, c.lo, nil)
+ }
+ }
+
+ return nodl(c.pos, OEQ, exprname, c.lo)
+}
+
+func allCaseExprsAreSideEffectFree(sw *Node) bool {
+ // In theory, we could be more aggressive, allowing any
+ // side-effect-free expressions in cases, but it's a bit
+ // tricky because some of that information is unavailable due
+ // to the introduction of temporaries during order.
+ // Restricting to constants is simple and probably powerful
+ // enough.
+
+ for _, ncase := range sw.List.Slice() {
+ if ncase.Op != OCASE {
+ Fatalf("switch string(byteslice) bad op: %v", ncase.Op)
+ }
+ for _, v := range ncase.List.Slice() {
+ if v.Op != OLITERAL {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// hasFall reports whether stmts ends with a "fallthrough" statement.
+func hasFall(stmts []*Node) (bool, src.XPos) {
+ // 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.
+
+ i := len(stmts) - 1
+ for i >= 0 && stmts[i].Op == OVARKILL {
+ i--
+ }
+ if i < 0 {
+ return false, src.NoXPos
+ }
+ return stmts[i].Op == OFALL, stmts[i].Pos
+}
+
+// walkTypeSwitch generates an AST that implements sw, where sw is a
+// type switch.
+func walkTypeSwitch(sw *Node) {
+ var s typeSwitch
+ s.facename = sw.Left.Right
+ sw.Left = nil
+
+ s.facename = walkexpr(s.facename, &sw.Ninit)
+ s.facename = copyexpr(s.facename, s.facename.Type, &sw.Nbody)
+ s.okname = temp(types.Types[TBOOL])
+
+ // Get interface descriptor word.
+ // For empty interfaces this will be the type.
+ // For non-empty interfaces this will be the itab.
+ itab := nod(OITAB, s.facename, nil)
+
+ // For empty interfaces, do:
+ // if e._type == nil {
+ // do nil case if it exists, otherwise default
+ // }
+ // h := e._type.hash
+ // Use a similar strategy for non-empty interfaces.
+ ifNil := nod(OIF, nil, nil)
+ ifNil.Left = nod(OEQ, itab, nodnil())
+ lineno = lineno.WithNotStmt() // disable statement marks after the first check.
+ ifNil.Left = typecheck(ifNil.Left, ctxExpr)
+ ifNil.Left = defaultlit(ifNil.Left, nil)
+ // ifNil.Nbody assigned at end.
+ sw.Nbody.Append(ifNil)
+
+ // Load hash from type or itab.
+ dotHash := nodSym(ODOTPTR, itab, nil)
+ dotHash.Type = types.Types[TUINT32]
+ dotHash.SetTypecheck(1)
+ if s.facename.Type.IsEmptyInterface() {
+ dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
+ } else {
+ dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime.itab
+ }
+ dotHash.SetBounded(true) // guaranteed not to fault
+ s.hashname = copyexpr(dotHash, dotHash.Type, &sw.Nbody)
+
+ br := nod(OBREAK, nil, nil)
+ var defaultGoto, nilGoto *Node
+ var body Nodes
+ for _, ncase := range sw.List.Slice() {
+ var caseVar *Node
+ if ncase.Rlist.Len() != 0 {
+ caseVar = ncase.Rlist.First()
+ }
+
+ // For single-type cases with an interface type,
+ // we initialize the case variable as part of the type assertion.
+ // In other cases, we initialize it in the body.
+ var singleType *types.Type
+ if ncase.List.Len() == 1 && ncase.List.First().Op == OTYPE {
+ singleType = ncase.List.First().Type
+ }
+ caseVarInitialized := false
+
+ label := autolabel(".s")
+ jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label))
+
+ if ncase.List.Len() == 0 { // default:
+ if defaultGoto != nil {
+ Fatalf("duplicate default case not detected during typechecking")
+ }
+ defaultGoto = jmp
+ }
+
+ for _, n1 := range ncase.List.Slice() {
+ if n1.isNil() { // case nil:
+ if nilGoto != nil {
+ Fatalf("duplicate nil case not detected during typechecking")
+ }
+ nilGoto = jmp
+ continue
+ }
+
+ if singleType != nil && singleType.IsInterface() {
+ s.Add(ncase.Pos, n1.Type, caseVar, jmp)
+ caseVarInitialized = true
+ } else {
+ s.Add(ncase.Pos, n1.Type, nil, jmp)
+ }
+ }
+
+ body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label)))
+ if caseVar != nil && !caseVarInitialized {
+ val := s.facename
+ if singleType != nil {
+ // We have a single concrete type. Extract the data.
+ if singleType.IsInterface() {
+ Fatalf("singleType interface should have been handled in Add")
+ }
+ val = ifaceData(ncase.Pos, s.facename, singleType)
+ }
+ l := []*Node{
+ nodl(ncase.Pos, ODCL, caseVar, nil),
+ nodl(ncase.Pos, OAS, caseVar, val),
+ }
+ typecheckslice(l, ctxStmt)
+ body.Append(l...)
+ }
+ body.Append(ncase.Nbody.Slice()...)
+ body.Append(br)
+ }
+ sw.List.Set(nil)
+
+ if defaultGoto == nil {
+ defaultGoto = br
+ }
+ if nilGoto == nil {
+ nilGoto = defaultGoto
+ }
+ ifNil.Nbody.Set1(nilGoto)
+
+ s.Emit(&sw.Nbody)
+ sw.Nbody.Append(defaultGoto)
+ sw.Nbody.AppendNodes(&body)
+
+ walkstmtlist(sw.Nbody.Slice())
+}
+
+// A typeSwitch walks a type switch.
+type typeSwitch struct {
+ // Temporary variables (i.e., ONAMEs) used by type switch dispatch logic:
+ facename *Node // value being type-switched on
+ hashname *Node // type hash of the value being type-switched on
+ okname *Node // boolean used for comma-ok type assertions
+
+ done Nodes
+ clauses []typeClause
+}
+
+type typeClause struct {
+ hash uint32
+ body Nodes
+}
+
+func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp *Node) {
+ var body Nodes
+ if caseVar != nil {
+ l := []*Node{
+ nodl(pos, ODCL, caseVar, nil),
+ nodl(pos, OAS, caseVar, nil),
+ }
+ typecheckslice(l, ctxStmt)
+ body.Append(l...)
+ } else {
+ caseVar = nblank
+ }
+
+ // cv, ok = iface.(type)
+ as := nodl(pos, OAS2, nil, nil)
+ as.List.Set2(caseVar, s.okname) // cv, ok =
+ dot := nodl(pos, ODOTTYPE, s.facename, nil)
+ dot.Type = typ // iface.(type)
+ as.Rlist.Set1(dot)
+ as = typecheck(as, ctxStmt)
+ as = walkexpr(as, &body)
+ body.Append(as)
+
+ // if ok { goto label }
+ nif := nodl(pos, OIF, nil, nil)
+ nif.Left = s.okname
+ nif.Nbody.Set1(jmp)
+ body.Append(nif)
+
+ if !typ.IsInterface() {
+ s.clauses = append(s.clauses, typeClause{
+ hash: typehash(typ),
+ body: body,
+ })
+ return
+ }
+
+ s.flush()
+ s.done.AppendNodes(&body)
+}
+
+func (s *typeSwitch) Emit(out *Nodes) {
+ s.flush()
+ out.AppendNodes(&s.done)
+}
+
+func (s *typeSwitch) flush() {
+ cc := s.clauses
+ s.clauses = nil
+ if len(cc) == 0 {
+ return
+ }
+
+ sort.Slice(cc, func(i, j int) bool { return cc[i].hash < cc[j].hash })
+
+ // Combine adjacent cases with the same hash.
+ merged := cc[:1]
+ for _, c := range cc[1:] {
+ last := &merged[len(merged)-1]
+ if last.hash == c.hash {
+ last.body.AppendNodes(&c.body)
+ } else {
+ merged = append(merged, c)
+ }
+ }
+ cc = merged
+
+ binarySearch(len(cc), &s.done,
+ func(i int) *Node {
+ return nod(OLE, s.hashname, nodintconst(int64(cc[i-1].hash)))
+ },
+ func(i int, nif *Node) {
+ // TODO(mdempsky): Omit hash equality check if
+ // there's only one type.
+ c := cc[i]
+ nif.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash)))
+ nif.Nbody.AppendNodes(&c.body)
+ },
+ )
+}
+
+// binarySearch constructs a binary search tree for handling n cases,
+// and appends it to out. It's used for efficiently implementing
+// switch statements.
+//
+// less(i) should return a boolean expression. If it evaluates true,
+// then cases before i will be tested; otherwise, cases i and later.
+//
+// base(i, nif) should setup nif (an OIF node) to test case i. In
+// particular, it should set nif.Left and nif.Nbody.
+func binarySearch(n int, out *Nodes, less func(i int) *Node, base func(i int, nif *Node)) {
+ const binarySearchMin = 4 // minimum number of cases for binary search
+
+ var do func(lo, hi int, out *Nodes)
+ do = func(lo, hi int, out *Nodes) {
+ n := hi - lo
+ if n < binarySearchMin {
+ for i := lo; i < hi; i++ {
+ nif := nod(OIF, nil, nil)
+ base(i, nif)
+ lineno = lineno.WithNotStmt()
+ nif.Left = typecheck(nif.Left, ctxExpr)
+ nif.Left = defaultlit(nif.Left, nil)
+ out.Append(nif)
+ out = &nif.Rlist
+ }
+ return
+ }
+
+ half := lo + n/2
+ nif := nod(OIF, nil, nil)
+ nif.Left = less(half)
+ lineno = lineno.WithNotStmt()
+ nif.Left = typecheck(nif.Left, ctxExpr)
+ nif.Left = defaultlit(nif.Left, nil)
+ do(lo, half, &nif.Nbody)
+ do(half, hi, &nif.Rlist)
+ out.Append(nif)
+ }
+
+ do(0, n, out)
+}
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
new file mode 100644
index 0000000..7b4a315
--- /dev/null
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -0,0 +1,1196 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// “Abstract” syntax representation.
+
+package gc
+
+import (
+ "cmd/compile/internal/ssa"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/src"
+ "sort"
+)
+
+// A Node is a single node in the syntax tree.
+// Actually the syntax tree is a syntax DAG, because there is only one
+// node with Op=ONAME for a given instance of a variable x.
+// The same is true for Op=OTYPE and Op=OLITERAL. See Node.mayBeShared.
+type Node struct {
+ // Tree structure.
+ // Generic recursive walks should follow these fields.
+ Left *Node
+ Right *Node
+ Ninit Nodes
+ Nbody Nodes
+ List Nodes
+ Rlist Nodes
+
+ // most nodes
+ Type *types.Type
+ Orig *Node // original form, for printing, and tracking copies of ONAMEs
+
+ // func
+ Func *Func
+
+ // ONAME, OTYPE, OPACK, OLABEL, some OLITERAL
+ Name *Name
+
+ Sym *types.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 ORESULT use it to indicate offset relative to their base address.
+ // - OSTRUCTKEY uses it to store the named field's offset.
+ // - Named OLITERALs use it to store their ambient iota value.
+ // - OINLMARK stores an index into the inlTree data structure.
+ // - OCLOSURE uses it to store ambient iota value, if any.
+ // Possibly still more uses. If you find any, document them.
+ Xoffset int64
+
+ Pos src.XPos
+
+ flags bitset32
+
+ Esc uint16 // EscXXX
+
+ Op Op
+ aux uint8
+}
+
+func (n *Node) ResetAux() {
+ n.aux = 0
+}
+
+func (n *Node) SubOp() Op {
+ switch n.Op {
+ case OASOP, ONAME:
+ default:
+ Fatalf("unexpected op: %v", n.Op)
+ }
+ return Op(n.aux)
+}
+
+func (n *Node) SetSubOp(op Op) {
+ switch n.Op {
+ case OASOP, ONAME:
+ default:
+ Fatalf("unexpected op: %v", n.Op)
+ }
+ n.aux = uint8(op)
+}
+
+func (n *Node) IndexMapLValue() bool {
+ if n.Op != OINDEXMAP {
+ Fatalf("unexpected op: %v", n.Op)
+ }
+ return n.aux != 0
+}
+
+func (n *Node) SetIndexMapLValue(b bool) {
+ if n.Op != OINDEXMAP {
+ Fatalf("unexpected op: %v", n.Op)
+ }
+ if b {
+ n.aux = 1
+ } else {
+ n.aux = 0
+ }
+}
+
+func (n *Node) TChanDir() types.ChanDir {
+ if n.Op != OTCHAN {
+ Fatalf("unexpected op: %v", n.Op)
+ }
+ return types.ChanDir(n.aux)
+}
+
+func (n *Node) SetTChanDir(dir types.ChanDir) {
+ if n.Op != OTCHAN {
+ Fatalf("unexpected op: %v", n.Op)
+ }
+ n.aux = uint8(dir)
+}
+
+func (n *Node) IsSynthetic() bool {
+ name := n.Sym.Name
+ return name[0] == '.' || name[0] == '~'
+}
+
+// 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 (
+ nodeClass, _ = iota, 1 << iota // PPARAM, PAUTO, PEXTERN, etc; three bits; first in the list because frequently accessed
+ _, _ // second nodeClass bit
+ _, _ // third nodeClass bit
+ nodeWalkdef, _ // tracks state during typecheckdef; 2 == loop detected; two bits
+ _, _ // second nodeWalkdef bit
+ nodeTypecheck, _ // tracks state during typechecking; 2 == loop detected; two bits
+ _, _ // second nodeTypecheck bit
+ nodeInitorder, _ // tracks state during init1; two bits
+ _, _ // second nodeInitorder bit
+ _, nodeHasBreak
+ _, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
+ _, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP
+ _, nodeIsDDD // is the argument variadic
+ _, nodeDiag // already printed error about this
+ _, nodeColas // OAS resulting from :=
+ _, nodeNonNil // guaranteed to be non-nil
+ _, nodeTransient // storage can be reused immediately after this statement
+ _, nodeBounded // bounds check unnecessary
+ _, nodeHasCall // expression contains a function call
+ _, nodeLikely // if statement condition likely
+ _, nodeHasVal // node.E contains a Val
+ _, nodeHasOpt // node.E contains an Opt
+ _, nodeEmbedded // ODCLFIELD embedded type
+)
+
+func (n *Node) Class() Class { return Class(n.flags.get3(nodeClass)) }
+func (n *Node) Walkdef() uint8 { return n.flags.get2(nodeWalkdef) }
+func (n *Node) Typecheck() uint8 { return n.flags.get2(nodeTypecheck) }
+func (n *Node) Initorder() uint8 { return n.flags.get2(nodeInitorder) }
+
+func (n *Node) HasBreak() bool { return n.flags&nodeHasBreak != 0 }
+func (n *Node) NoInline() bool { return n.flags&nodeNoInline != 0 }
+func (n *Node) Implicit() bool { return n.flags&nodeImplicit != 0 }
+func (n *Node) IsDDD() bool { return n.flags&nodeIsDDD != 0 }
+func (n *Node) Diag() bool { return n.flags&nodeDiag != 0 }
+func (n *Node) Colas() bool { return n.flags&nodeColas != 0 }
+func (n *Node) NonNil() bool { return n.flags&nodeNonNil != 0 }
+func (n *Node) Transient() bool { return n.flags&nodeTransient != 0 }
+func (n *Node) Bounded() bool { return n.flags&nodeBounded != 0 }
+func (n *Node) HasCall() bool { return n.flags&nodeHasCall != 0 }
+func (n *Node) Likely() bool { return n.flags&nodeLikely != 0 }
+func (n *Node) HasVal() bool { return n.flags&nodeHasVal != 0 }
+func (n *Node) HasOpt() bool { return n.flags&nodeHasOpt != 0 }
+func (n *Node) Embedded() bool { return n.flags&nodeEmbedded != 0 }
+
+func (n *Node) SetClass(b Class) { n.flags.set3(nodeClass, uint8(b)) }
+func (n *Node) SetWalkdef(b uint8) { n.flags.set2(nodeWalkdef, b) }
+func (n *Node) SetTypecheck(b uint8) { n.flags.set2(nodeTypecheck, b) }
+func (n *Node) SetInitorder(b uint8) { n.flags.set2(nodeInitorder, b) }
+
+func (n *Node) SetHasBreak(b bool) { n.flags.set(nodeHasBreak, b) }
+func (n *Node) SetNoInline(b bool) { n.flags.set(nodeNoInline, b) }
+func (n *Node) SetImplicit(b bool) { n.flags.set(nodeImplicit, b) }
+func (n *Node) SetIsDDD(b bool) { n.flags.set(nodeIsDDD, b) }
+func (n *Node) SetDiag(b bool) { n.flags.set(nodeDiag, b) }
+func (n *Node) SetColas(b bool) { n.flags.set(nodeColas, b) }
+func (n *Node) SetTransient(b bool) { n.flags.set(nodeTransient, b) }
+func (n *Node) SetHasCall(b bool) { n.flags.set(nodeHasCall, b) }
+func (n *Node) SetLikely(b bool) { n.flags.set(nodeLikely, b) }
+func (n *Node) SetHasVal(b bool) { n.flags.set(nodeHasVal, b) }
+func (n *Node) SetHasOpt(b bool) { n.flags.set(nodeHasOpt, b) }
+func (n *Node) SetEmbedded(b bool) { n.flags.set(nodeEmbedded, b) }
+
+// MarkNonNil marks a pointer n as being guaranteed non-nil,
+// on all code paths, at all times.
+// During conversion to SSA, non-nil pointers won't have nil checks
+// inserted before dereferencing. See state.exprPtr.
+func (n *Node) MarkNonNil() {
+ if !n.Type.IsPtr() && !n.Type.IsUnsafePtr() {
+ Fatalf("MarkNonNil(%v), type %v", n, n.Type)
+ }
+ n.flags.set(nodeNonNil, true)
+}
+
+// SetBounded indicates whether operation n does not need safety checks.
+// When n is an index or slice operation, n does not need bounds checks.
+// When n is a dereferencing operation, n does not need nil checks.
+// When n is a makeslice+copy operation, n does not need length and cap checks.
+func (n *Node) SetBounded(b bool) {
+ switch n.Op {
+ case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
+ // No bounds checks needed.
+ case ODOTPTR, ODEREF:
+ // No nil check needed.
+ case OMAKESLICECOPY:
+ // No length and cap checks needed
+ // since new slice and copied over slice data have same length.
+ default:
+ Fatalf("SetBounded(%v)", n)
+ }
+ n.flags.set(nodeBounded, b)
+}
+
+// MarkReadonly indicates that n is an ONAME with readonly contents.
+func (n *Node) MarkReadonly() {
+ if n.Op != ONAME {
+ Fatalf("Node.MarkReadonly %v", n.Op)
+ }
+ n.Name.SetReadonly(true)
+ // Mark the linksym as readonly immediately
+ // so that the SSA backend can use this information.
+ // It will be overridden later during dumpglobls.
+ n.Sym.Linksym().Type = objabi.SRODATA
+}
+
+// Val returns the Val for the node.
+func (n *Node) Val() Val {
+ if !n.HasVal() {
+ return Val{}
+ }
+ return Val{n.E}
+}
+
+// SetVal sets the Val for the node, which must not have been used with SetOpt.
+func (n *Node) SetVal(v Val) {
+ if n.HasOpt() {
+ Debug.h = 1
+ Dump("have Opt", n)
+ Fatalf("have Opt")
+ }
+ n.SetHasVal(true)
+ n.E = v.U
+}
+
+// Opt returns the optimizer data for the node.
+func (n *Node) Opt() interface{} {
+ if !n.HasOpt() {
+ return nil
+ }
+ return n.E
+}
+
+// SetOpt sets the optimizer data for the node, which must not have been used with SetVal.
+// SetOpt(nil) is ignored for Vals to simplify call sites that are clearing Opts.
+func (n *Node) SetOpt(x interface{}) {
+ if x == nil && n.HasVal() {
+ return
+ }
+ if n.HasVal() {
+ Debug.h = 1
+ Dump("have Val", n)
+ Fatalf("have Val")
+ }
+ n.SetHasOpt(true)
+ n.E = x
+}
+
+func (n *Node) Iota() int64 {
+ return n.Xoffset
+}
+
+func (n *Node) SetIota(x int64) {
+ n.Xoffset = x
+}
+
+// mayBeShared reports whether n may occur in multiple places in the AST.
+// Extra care must be taken when mutating such a node.
+func (n *Node) mayBeShared() bool {
+ switch n.Op {
+ case ONAME, OLITERAL, OTYPE:
+ return true
+ }
+ return false
+}
+
+// isMethodExpression reports whether n represents a method expression T.M.
+func (n *Node) isMethodExpression() bool {
+ return n.Op == ONAME && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME
+}
+
+// funcname returns the name (without the package) of the function n.
+func (n *Node) funcname() string {
+ if n == nil || n.Func == nil || n.Func.Nname == nil {
+ return "<nil>"
+ }
+ return n.Func.Nname.Sym.Name
+}
+
+// pkgFuncName returns the name of the function referenced by n, with package prepended.
+// This differs from the compiler's internal convention where local functions lack a package
+// because the ultimate consumer of this is a human looking at an IDE; package is only empty
+// if the compilation package is actually the empty string.
+func (n *Node) pkgFuncName() string {
+ var s *types.Sym
+ if n == nil {
+ return "<nil>"
+ }
+ if n.Op == ONAME {
+ s = n.Sym
+ } else {
+ if n.Func == nil || n.Func.Nname == nil {
+ return "<nil>"
+ }
+ s = n.Func.Nname.Sym
+ }
+ pkg := s.Pkg
+
+ p := myimportpath
+ if pkg != nil && pkg.Path != "" {
+ p = pkg.Path
+ }
+ if p == "" {
+ return s.Name
+ }
+ return p + "." + s.Name
+}
+
+// The compiler needs *Node to be assignable to cmd/compile/internal/ssa.Sym.
+func (n *Node) CanBeAnSSASym() {
+}
+
+// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
+type Name struct {
+ Pack *Node // real package for import . names
+ Pkg *types.Pkg // pkg for OPACK nodes
+ // For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
+ // For a closure var, the ONAME node of the outer captured variable
+ Defn *Node
+ // The ODCLFUNC node (for a static function/method or a closure) in which
+ // local variable or param is declared.
+ Curfn *Node
+ Param *Param // additional fields for ONAME, OTYPE
+ Decldepth int32 // declaration loop depth, increased for every loop or label
+ // Unique number for ONAME nodes within a function. Function outputs
+ // (results) are numbered starting at one, followed by function inputs
+ // (parameters), and then local variables. Vargen is used to distinguish
+ // local variables/params with the same name.
+ Vargen int32
+ flags bitset16
+}
+
+const (
+ nameCaptured = 1 << iota // is the variable captured by a closure
+ nameReadonly
+ nameByval // is the variable captured by value or by reference
+ nameNeedzero // if it contains pointers, needs to be zeroed on function entry
+ nameAutoTemp // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
+ nameUsed // for variable declared and not used error
+ nameIsClosureVar // PAUTOHEAP closure pseudo-variable; original at n.Name.Defn
+ nameIsOutputParamHeapAddr // pointer to a result parameter's heap copy
+ nameAssigned // is the variable ever assigned to
+ nameAddrtaken // address taken, even if not moved to heap
+ nameInlFormal // PAUTO created by inliner, derived from callee formal
+ nameInlLocal // PAUTO created by inliner, derived from callee local
+ nameOpenDeferSlot // if temporary var storing info for open-coded defers
+ nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
+)
+
+func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 }
+func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 }
+func (n *Name) Byval() bool { return n.flags&nameByval != 0 }
+func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 }
+func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
+func (n *Name) Used() bool { return n.flags&nameUsed != 0 }
+func (n *Name) IsClosureVar() bool { return n.flags&nameIsClosureVar != 0 }
+func (n *Name) IsOutputParamHeapAddr() bool { return n.flags&nameIsOutputParamHeapAddr != 0 }
+func (n *Name) Assigned() bool { return n.flags&nameAssigned != 0 }
+func (n *Name) Addrtaken() bool { return n.flags&nameAddrtaken != 0 }
+func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0 }
+func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 }
+func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 }
+func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 }
+
+func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) }
+func (n *Name) SetReadonly(b bool) { n.flags.set(nameReadonly, b) }
+func (n *Name) SetByval(b bool) { n.flags.set(nameByval, b) }
+func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
+func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
+func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
+func (n *Name) SetIsClosureVar(b bool) { n.flags.set(nameIsClosureVar, b) }
+func (n *Name) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nameIsOutputParamHeapAddr, b) }
+func (n *Name) SetAssigned(b bool) { n.flags.set(nameAssigned, b) }
+func (n *Name) SetAddrtaken(b bool) { n.flags.set(nameAddrtaken, b) }
+func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b) }
+func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) }
+func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) }
+func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) }
+
+type Param struct {
+ Ntype *Node
+ Heapaddr *Node // temp holding heap address of param
+
+ // ONAME PAUTOHEAP
+ Stackcopy *Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only)
+
+ // ONAME closure linkage
+ // Consider:
+ //
+ // func f() {
+ // x := 1 // x1
+ // func() {
+ // use(x) // x2
+ // func() {
+ // use(x) // x3
+ // --- parser is here ---
+ // }()
+ // }()
+ // }
+ //
+ // There is an original declaration of x and then a chain of mentions of x
+ // leading into the current function. Each time x is mentioned in a new closure,
+ // we create a variable representing x for use in that specific closure,
+ // since the way you get to x is different in each closure.
+ //
+ // Let's number the specific variables as shown in the code:
+ // x1 is the original x, x2 is when mentioned in the closure,
+ // and x3 is when mentioned in the closure in the closure.
+ //
+ // We keep these linked (assume N > 1):
+ //
+ // - x1.Defn = original declaration statement for x (like most variables)
+ // - x1.Innermost = current innermost closure x (in this case x3), or nil for none
+ // - x1.IsClosureVar() = false
+ //
+ // - xN.Defn = x1, N > 1
+ // - xN.IsClosureVar() = true, N > 1
+ // - x2.Outer = nil
+ // - xN.Outer = x(N-1), N > 2
+ //
+ //
+ // When we look up x in the symbol table, we always get x1.
+ // Then we can use x1.Innermost (if not nil) to get the x
+ // for the innermost known closure function,
+ // but the first reference in a closure will find either no x1.Innermost
+ // or an x1.Innermost with .Funcdepth < Funcdepth.
+ // In that case, a new xN must be created, linked in with:
+ //
+ // xN.Defn = x1
+ // xN.Outer = x1.Innermost
+ // x1.Innermost = xN
+ //
+ // When we finish the function, we'll process its closure variables
+ // and find xN and pop it off the list using:
+ //
+ // x1 := xN.Defn
+ // x1.Innermost = xN.Outer
+ //
+ // We leave x1.Innermost set so that we can still get to the original
+ // variable quickly. Not shown here, but once we're
+ // done parsing a function and no longer need xN.Outer for the
+ // lexical x reference links as described above, funcLit
+ // recomputes xN.Outer as the semantic x reference link tree,
+ // even filling in x in intermediate closures that might not
+ // have mentioned it along the way to inner closures that did.
+ // See funcLit for details.
+ //
+ // During the eventual compilation, then, for closure variables we have:
+ //
+ // xN.Defn = original variable
+ // xN.Outer = variable captured in next outward scope
+ // to make closure where xN appears
+ //
+ // Because of the sharding of pieces of the node, x.Defn means x.Name.Defn
+ // and x.Innermost/Outer means x.Name.Param.Innermost/Outer.
+ Innermost *Node
+ Outer *Node
+
+ // OTYPE & ONAME //go:embed info,
+ // sharing storage to reduce gc.Param size.
+ // Extra is nil, or else *Extra is a *paramType or an *embedFileList.
+ Extra *interface{}
+}
+
+type paramType struct {
+ flag PragmaFlag
+ alias bool
+}
+
+type irEmbed struct {
+ Pos src.XPos
+ Patterns []string
+}
+
+type embedList []irEmbed
+
+// Pragma returns the PragmaFlag for p, which must be for an OTYPE.
+func (p *Param) Pragma() PragmaFlag {
+ if p.Extra == nil {
+ return 0
+ }
+ return (*p.Extra).(*paramType).flag
+}
+
+// SetPragma sets the PragmaFlag for p, which must be for an OTYPE.
+func (p *Param) SetPragma(flag PragmaFlag) {
+ if p.Extra == nil {
+ if flag == 0 {
+ return
+ }
+ p.Extra = new(interface{})
+ *p.Extra = &paramType{flag: flag}
+ return
+ }
+ (*p.Extra).(*paramType).flag = flag
+}
+
+// Alias reports whether p, which must be for an OTYPE, is a type alias.
+func (p *Param) Alias() bool {
+ if p.Extra == nil {
+ return false
+ }
+ t, ok := (*p.Extra).(*paramType)
+ if !ok {
+ return false
+ }
+ return t.alias
+}
+
+// SetAlias sets whether p, which must be for an OTYPE, is a type alias.
+func (p *Param) SetAlias(alias bool) {
+ if p.Extra == nil {
+ if !alias {
+ return
+ }
+ p.Extra = new(interface{})
+ *p.Extra = &paramType{alias: alias}
+ return
+ }
+ (*p.Extra).(*paramType).alias = alias
+}
+
+// EmbedList returns the list of embedded files for p,
+// which must be for an ONAME var.
+func (p *Param) EmbedList() []irEmbed {
+ if p.Extra == nil {
+ return nil
+ }
+ return *(*p.Extra).(*embedList)
+}
+
+// SetEmbedList sets the list of embedded files for p,
+// which must be for an ONAME var.
+func (p *Param) SetEmbedList(list []irEmbed) {
+ if p.Extra == nil {
+ if len(list) == 0 {
+ return
+ }
+ f := embedList(list)
+ p.Extra = new(interface{})
+ *p.Extra = &f
+ return
+ }
+ *(*p.Extra).(*embedList) = list
+}
+
+// Functions
+//
+// A simple function declaration is represented as an ODCLFUNC node f
+// and an ONAME node n. They're linked to one another through
+// f.Func.Nname == n and n.Name.Defn == f. When functions are
+// referenced by name in an expression, the function's ONAME node is
+// used directly.
+//
+// Function names have n.Class() == PFUNC. This distinguishes them
+// from variables of function type.
+//
+// Confusingly, n.Func and f.Func both exist, but commonly point to
+// different Funcs. (Exception: an OCALLPART's Func does point to its
+// ODCLFUNC's Func.)
+//
+// A method declaration is represented like functions, except n.Sym
+// will be the qualified method name (e.g., "T.m") and
+// f.Func.Shortname is the bare method name (e.g., "m").
+//
+// Method expressions are represented as ONAME/PFUNC nodes like
+// function names, but their Left and Right fields still point to the
+// type and method, respectively. They can be distinguished from
+// normal functions with isMethodExpression. Also, unlike function
+// name nodes, method expression nodes exist for each method
+// expression. The declaration ONAME can be accessed with
+// x.Type.Nname(), where x is the method expression ONAME node.
+//
+// Method values are represented by ODOTMETH/ODOTINTER when called
+// immediately, and OCALLPART otherwise. They are like method
+// expressions, except that for ODOTMETH/ODOTINTER the method name is
+// stored in Sym instead of Right.
+//
+// Closures are represented by OCLOSURE node c. They link back and
+// forth with the ODCLFUNC via Func.Closure; that is, c.Func.Closure
+// == f and f.Func.Closure == c.
+//
+// Function bodies are stored in f.Nbody, and inline function bodies
+// are stored in n.Func.Inl. Pragmas are stored in f.Func.Pragma.
+//
+// Imported functions skip the ODCLFUNC, so n.Name.Defn is nil. They
+// also use Dcl instead of Inldcl.
+
+// Func holds Node fields used only with function-like nodes.
+type Func struct {
+ Shortname *types.Sym
+ // Extra entry code for the function. For example, allocate and initialize
+ // memory for escaping parameters. However, just for OCLOSURE, Enter is a
+ // list of ONAME nodes of captured variables
+ Enter Nodes
+ Exit Nodes
+ // ONAME nodes for closure params, each should have closurevar set
+ Cvars Nodes
+ // ONAME nodes for all params/locals for this func/closure, does NOT
+ // include closurevars until transformclosure runs.
+ Dcl []*Node
+
+ // Parents records the parent scope of each scope within a
+ // function. The root scope (0) has no parent, so the i'th
+ // scope's parent is stored at Parents[i-1].
+ Parents []ScopeID
+
+ // Marks records scope boundary changes.
+ Marks []Mark
+
+ // Closgen tracks how many closures have been generated within
+ // this function. Used by closurename for creating unique
+ // function names.
+ Closgen int
+
+ FieldTrack map[*types.Sym]struct{}
+ DebugInfo *ssa.FuncDebug
+ Ntype *Node // signature
+ Top int // top context (ctxCallee, etc)
+ Closure *Node // OCLOSURE <-> ODCLFUNC (see header comment above)
+ Nname *Node // The ONAME node associated with an ODCLFUNC (both have same Type)
+ lsym *obj.LSym
+
+ Inl *Inline
+
+ Label int32 // largest auto-generated label in this function
+
+ Endlineno src.XPos
+ WBPos src.XPos // position of first write barrier; see SetWBPos
+
+ Pragma PragmaFlag // go:xxx function annotations
+
+ flags bitset16
+ numDefers int // number of defer calls in the function
+ numReturns int // number of explicit returns in the function
+
+ // nwbrCalls records the LSyms of functions called by this
+ // function for go:nowritebarrierrec analysis. Only filled in
+ // if nowritebarrierrecCheck != nil.
+ nwbrCalls *[]nowritebarrierrecCallSym
+}
+
+// An Inline holds fields used for function bodies that can be inlined.
+type Inline struct {
+ Cost int32 // heuristic cost of inlining this function
+
+ // Copies of Func.Dcl and Nbody for use during inlining.
+ Dcl []*Node
+ Body []*Node
+}
+
+// A Mark represents a scope boundary.
+type Mark struct {
+ // Pos is the position of the token that marks the scope
+ // change.
+ Pos src.XPos
+
+ // Scope identifies the innermost scope to the right of Pos.
+ Scope ScopeID
+}
+
+// A ScopeID represents a lexical scope within a function.
+type ScopeID int32
+
+const (
+ funcDupok = 1 << iota // duplicate definitions ok
+ funcWrapper // is method wrapper
+ funcNeedctxt // function uses context register (has closure variables)
+ funcReflectMethod // function calls reflect.Type.Method or MethodByName
+ // true if closure inside a function; false if a simple function or a
+ // closure in a global variable initialization
+ funcIsHiddenClosure
+ funcHasDefer // contains a defer statement
+ funcNilCheckDisabled // disable nil checks when compiling this function
+ funcInlinabilityChecked // inliner has already determined whether the function is inlinable
+ funcExportInline // include inline body in export data
+ funcInstrumentBody // add race/msan instrumentation during SSA construction
+ funcOpenCodedDeferDisallowed // can't do open-coded defers
+)
+
+func (f *Func) Dupok() bool { return f.flags&funcDupok != 0 }
+func (f *Func) Wrapper() bool { return f.flags&funcWrapper != 0 }
+func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 }
+func (f *Func) ReflectMethod() bool { return f.flags&funcReflectMethod != 0 }
+func (f *Func) IsHiddenClosure() bool { return f.flags&funcIsHiddenClosure != 0 }
+func (f *Func) HasDefer() bool { return f.flags&funcHasDefer != 0 }
+func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 }
+func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 }
+func (f *Func) ExportInline() bool { return f.flags&funcExportInline != 0 }
+func (f *Func) InstrumentBody() bool { return f.flags&funcInstrumentBody != 0 }
+func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
+
+func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) }
+func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) }
+func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) }
+func (f *Func) SetReflectMethod(b bool) { f.flags.set(funcReflectMethod, b) }
+func (f *Func) SetIsHiddenClosure(b bool) { f.flags.set(funcIsHiddenClosure, b) }
+func (f *Func) SetHasDefer(b bool) { f.flags.set(funcHasDefer, b) }
+func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) }
+func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) }
+func (f *Func) SetExportInline(b bool) { f.flags.set(funcExportInline, b) }
+func (f *Func) SetInstrumentBody(b bool) { f.flags.set(funcInstrumentBody, b) }
+func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
+
+func (f *Func) setWBPos(pos src.XPos) {
+ if Debug_wb != 0 {
+ Warnl(pos, "write barrier")
+ }
+ if !f.WBPos.IsKnown() {
+ f.WBPos = pos
+ }
+}
+
+//go:generate stringer -type=Op -trimprefix=O
+
+type Op uint8
+
+// Node ops.
+const (
+ OXXX Op = iota
+
+ // names
+ ONAME // var or func name
+ // Unnamed arg or return value: f(int, string) (int, error) { etc }
+ // Also used for a qualified package identifier that hasn't been resolved yet.
+ ONONAME
+ OTYPE // type name
+ OPACK // import
+ OLITERAL // literal
+
+ // expressions
+ OADD // Left + Right
+ OSUB // Left - Right
+ OOR // Left | Right
+ OXOR // Left ^ Right
+ OADDSTR // +{List} (string addition, list elements are strings)
+ OADDR // &Left
+ OANDAND // Left && Right
+ OAPPEND // append(List); after walk, Left may contain elem type descriptor
+ OBYTES2STR // Type(Left) (Type is string, Left is a []byte)
+ OBYTES2STRTMP // Type(Left) (Type is string, Left is a []byte, ephemeral)
+ ORUNES2STR // Type(Left) (Type is string, Left is a []rune)
+ OSTR2BYTES // Type(Left) (Type is []byte, Left is a string)
+ OSTR2BYTESTMP // Type(Left) (Type is []byte, Left is a string, ephemeral)
+ OSTR2RUNES // Type(Left) (Type is []rune, Left is a string)
+ // Left = Right or (if Colas=true) Left := Right
+ // If Colas, then Ninit includes a DCL node for Left.
+ OAS
+ // List = Rlist (x, y, z = a, b, c) or (if Colas=true) List := Rlist
+ // If Colas, then Ninit includes DCL nodes for List
+ OAS2
+ OAS2DOTTYPE // List = Right (x, ok = I.(int))
+ OAS2FUNC // List = Right (x, y = f())
+ OAS2MAPR // List = Right (x, ok = m["foo"])
+ OAS2RECV // List = Right (x, ok = <-c)
+ OASOP // Left Etype= Right (x += y)
+ OCALL // Left(List) (function call, method call or type conversion)
+
+ // OCALLFUNC, OCALLMETH, and OCALLINTER have the same structure.
+ // Prior to walk, they are: Left(List), where List is all regular arguments.
+ // After walk, List is a series of assignments to temporaries,
+ // and Rlist is an updated set of arguments.
+ // Nbody is all OVARLIVE nodes that are attached to OCALLxxx.
+ // TODO(josharian/khr): Use Ninit instead of List for the assignments to temporaries. See CL 114797.
+ OCALLFUNC // Left(List/Rlist) (function call f(args))
+ OCALLMETH // Left(List/Rlist) (direct method call x.Method(args))
+ OCALLINTER // Left(List/Rlist) (interface method call x.Method(args))
+ OCALLPART // Left.Right (method expression x.Method, not called)
+ OCAP // cap(Left)
+ OCLOSE // close(Left)
+ OCLOSURE // func Type { Func.Closure.Nbody } (func literal)
+ 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)
+ OSLICELIT // Type{List} (composite literal, Type is slice) Right.Int64() = slice length.
+ OPTRLIT // &Left (left is composite literal)
+ OCONV // Type(Left) (type conversion)
+ OCONVIFACE // Type(Left) (type conversion, to interface)
+ OCONVNOP // Type(Left) (type conversion, no effect)
+ OCOPY // copy(Left, Right)
+ ODCL // var Left (declares Left of type Left.Type)
+
+ // Used during parsing but don't last.
+ ODCLFUNC // func f() or func (r) f()
+ ODCLFIELD // struct field, interface field, or func/method argument/return value.
+ ODCLCONST // const pi = 3.14
+ ODCLTYPE // type Int int or type Int = int
+
+ ODELETE // delete(List)
+ ODOT // Left.Sym (Left is of struct type)
+ ODOTPTR // Left.Sym (Left is of pointer to struct type)
+ ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
+ ODOTINTER // Left.Sym (Left is interface, Right is method name)
+ OXDOT // Left.Sym (before rewrite to one of the preceding)
+ ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
+ ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
+ OEQ // Left == Right
+ ONE // Left != Right
+ OLT // Left < Right
+ OLE // Left <= Right
+ OGE // Left >= Right
+ OGT // Left > Right
+ ODEREF // *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)
+ 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)
+ OMAKEMAP // make(Type, Left) (type is map)
+ OMAKESLICE // make(Type, Left, Right) (type is slice)
+ OMAKESLICECOPY // makeslicecopy(Type, Left, Right) (type is slice; Left is length and Right is the copied from slice)
+ // OMAKESLICECOPY is created by the order pass and corresponds to:
+ // s = make(Type, Left); copy(s, Right)
+ //
+ // Bounded can be set on the node when Left == len(Right) is known at compile time.
+ //
+ // This node is created so the walk pass can optimize this pattern which would
+ // otherwise be hard to detect after the order pass.
+ OMUL // Left * Right
+ ODIV // Left / Right
+ OMOD // Left % Right
+ OLSH // Left << Right
+ ORSH // Left >> Right
+ OAND // Left & Right
+ OANDNOT // Left &^ Right
+ ONEW // new(Left); corresponds to calls to new in source code
+ ONEWOBJ // runtime.newobject(n.Type); introduced by walk; Left is type descriptor
+ ONOT // !Left
+ OBITNOT // ^Left
+ OPLUS // +Left
+ ONEG // -Left
+ OOROR // Left || Right
+ OPANIC // panic(Left)
+ OPRINT // print(List)
+ OPRINTN // println(List)
+ OPAREN // (Left)
+ OSEND // Left <- Right
+ 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)
+ OSLICEHEADER // sliceheader{Left, List[0], List[1]} (Left is unsafe.Pointer, List[0] is length, List[1] is capacity)
+ ORECOVER // recover()
+ ORECV // <-Left
+ ORUNESTR // Type(Left) (Type is string, Left is rune)
+ OSELRECV // Left = <-Right.Left: (appears as .Left of OCASE; Right.Op == ORECV)
+ OSELRECV2 // List = <-Right.Left: (appears as .Left of OCASE; count(List) == 2, Right.Op == ORECV)
+ OIOTA // iota
+ OREAL // real(Left)
+ OIMAG // imag(Left)
+ OCOMPLEX // complex(Left, Right) or complex(List[0]) where List[0] is a 2-result function call
+ OALIGNOF // unsafe.Alignof(Left)
+ OOFFSETOF // unsafe.Offsetof(Left)
+ OSIZEOF // unsafe.Sizeof(Left)
+
+ // statements
+ OBLOCK // { List } (block of code)
+ OBREAK // break [Sym]
+ // OCASE: case List: Nbody (List==nil means default)
+ // For OTYPESW, List is a OTYPE node for the specified type (or OLITERAL
+ // for nil), and, if a type-switch variable is specified, Rlist is an
+ // ONAME for the version of the type-switch variable with the specified
+ // type.
+ OCASE
+ OCONTINUE // continue [Sym]
+ ODEFER // defer Left (Left must be call)
+ OEMPTY // no-op (empty statement)
+ OFALL // fallthrough
+ OFOR // for Ninit; Left; Right { Nbody }
+ // OFORUNTIL is like OFOR, but the test (Left) is applied after the body:
+ // Ninit
+ // top: { Nbody } // Execute the body at least once
+ // cont: Right
+ // if Left { // And then test the loop condition
+ // List // Before looping to top, execute List
+ // goto top
+ // }
+ // OFORUNTIL is created by walk. There's no way to write this in Go code.
+ OFORUNTIL
+ OGOTO // goto Sym
+ OIF // if Ninit; Left { Nbody } else { Rlist }
+ OLABEL // Sym:
+ OGO // go Left (Left must be call)
+ ORANGE // for List = range Right { Nbody }
+ ORETURN // return List
+ OSELECT // select { List } (List is list of OCASE)
+ OSWITCH // switch Ninit; Left { List } (List is a list of OCASE)
+ // OTYPESW: Left := Right.(type) (appears as .Left of OSWITCH)
+ // Left is nil if there is no type-switch variable
+ OTYPESW
+
+ // types
+ OTCHAN // chan int
+ OTMAP // map[string]int
+ OTSTRUCT // struct{}
+ OTINTER // interface{}
+ // OTFUNC: func() - Left is receiver field, List is list of param fields, Rlist is
+ // list of result fields.
+ OTFUNC
+ OTARRAY // []int, [8]int, [N]int or [...]int
+
+ // misc
+ ODDD // func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}.
+ 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
+ OVARDEF // variable is about to be fully initialized
+ OVARKILL // variable is dead
+ OVARLIVE // variable is alive
+ ORESULT // result of a function call; Xoffset is stack offset
+ OINLMARK // start of an inlined body, with file/line of caller. Xoffset is an index into the inline tree.
+
+ // arch-specific opcodes
+ ORETJMP // return to other function
+ OGETG // runtime.getg() (read g pointer)
+
+ OEND
+)
+
+// Nodes is a pointer to a slice of *Node.
+// For fields that are not used in most nodes, this is used instead of
+// a slice to save space.
+type Nodes struct{ slice *[]*Node }
+
+// asNodes returns a slice of *Node as a Nodes value.
+func asNodes(s []*Node) Nodes {
+ return Nodes{&s}
+}
+
+// Slice returns the entries in Nodes as a slice.
+// Changes to the slice entries (as in s[i] = n) will be reflected in
+// the Nodes.
+func (n Nodes) Slice() []*Node {
+ if n.slice == nil {
+ return nil
+ }
+ return *n.slice
+}
+
+// Len returns the number of entries in Nodes.
+func (n Nodes) Len() int {
+ if n.slice == nil {
+ return 0
+ }
+ return len(*n.slice)
+}
+
+// Index returns the i'th element of Nodes.
+// It panics if n does not have at least i+1 elements.
+func (n Nodes) Index(i int) *Node {
+ return (*n.slice)[i]
+}
+
+// First returns the first element of Nodes (same as n.Index(0)).
+// It panics if n has no elements.
+func (n Nodes) First() *Node {
+ return (*n.slice)[0]
+}
+
+// Second returns the second element of Nodes (same as n.Index(1)).
+// It panics if n has fewer than two elements.
+func (n Nodes) Second() *Node {
+ return (*n.slice)[1]
+}
+
+// Set sets n to a slice.
+// This takes ownership of the slice.
+func (n *Nodes) Set(s []*Node) {
+ if len(s) == 0 {
+ n.slice = nil
+ } else {
+ // Copy s and take address of t rather than s to avoid
+ // allocation in the case where len(s) == 0 (which is
+ // over 3x more common, dynamically, for make.bash).
+ t := s
+ n.slice = &t
+ }
+}
+
+// Set1 sets n to a slice containing a single node.
+func (n *Nodes) Set1(n1 *Node) {
+ n.slice = &[]*Node{n1}
+}
+
+// Set2 sets n to a slice containing two nodes.
+func (n *Nodes) Set2(n1, n2 *Node) {
+ n.slice = &[]*Node{n1, n2}
+}
+
+// Set3 sets n to a slice containing three nodes.
+func (n *Nodes) Set3(n1, n2, n3 *Node) {
+ n.slice = &[]*Node{n1, n2, n3}
+}
+
+// MoveNodes sets n to the contents of n2, then clears n2.
+func (n *Nodes) MoveNodes(n2 *Nodes) {
+ n.slice = n2.slice
+ n2.slice = nil
+}
+
+// SetIndex sets the i'th element of Nodes to node.
+// It panics if n does not have at least i+1 elements.
+func (n Nodes) SetIndex(i int, node *Node) {
+ (*n.slice)[i] = node
+}
+
+// SetFirst sets the first element of Nodes to node.
+// It panics if n does not have at least one elements.
+func (n Nodes) SetFirst(node *Node) {
+ (*n.slice)[0] = node
+}
+
+// SetSecond sets the second element of Nodes to node.
+// It panics if n does not have at least two elements.
+func (n Nodes) SetSecond(node *Node) {
+ (*n.slice)[1] = node
+}
+
+// Addr returns the address of the i'th element of Nodes.
+// It panics if n does not have at least i+1 elements.
+func (n Nodes) Addr(i int) **Node {
+ return &(*n.slice)[i]
+}
+
+// Append appends entries to Nodes.
+func (n *Nodes) Append(a ...*Node) {
+ if len(a) == 0 {
+ return
+ }
+ if n.slice == nil {
+ s := make([]*Node, len(a))
+ copy(s, a)
+ n.slice = &s
+ return
+ }
+ *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 {
+ case n2.slice == nil:
+ case n.slice == nil:
+ n.slice = n2.slice
+ default:
+ *n.slice = append(*n.slice, *n2.slice...)
+ }
+ n2.slice = nil
+}
+
+// inspect invokes f on each node in an AST in depth-first order.
+// If f(n) returns false, inspect skips visiting n's children.
+func inspect(n *Node, f func(*Node) bool) {
+ if n == nil || !f(n) {
+ return
+ }
+ inspectList(n.Ninit, f)
+ inspect(n.Left, f)
+ inspect(n.Right, f)
+ inspectList(n.List, f)
+ inspectList(n.Nbody, f)
+ inspectList(n.Rlist, f)
+}
+
+func inspectList(l Nodes, f func(*Node) bool) {
+ for _, n := range l.Slice() {
+ inspect(n, f)
+ }
+}
+
+// nodeQueue is a FIFO queue of *Node. The zero value of nodeQueue is
+// a ready-to-use empty queue.
+type nodeQueue struct {
+ ring []*Node
+ head, tail int
+}
+
+// empty reports whether q contains no Nodes.
+func (q *nodeQueue) empty() bool {
+ return q.head == q.tail
+}
+
+// pushRight appends n to the right of the queue.
+func (q *nodeQueue) pushRight(n *Node) {
+ if len(q.ring) == 0 {
+ q.ring = make([]*Node, 16)
+ } else if q.head+len(q.ring) == q.tail {
+ // Grow the ring.
+ nring := make([]*Node, len(q.ring)*2)
+ // Copy the old elements.
+ part := q.ring[q.head%len(q.ring):]
+ if q.tail-q.head <= len(part) {
+ part = part[:q.tail-q.head]
+ copy(nring, part)
+ } else {
+ pos := copy(nring, part)
+ copy(nring[pos:], q.ring[:q.tail%len(q.ring)])
+ }
+ q.ring, q.head, q.tail = nring, 0, q.tail-q.head
+ }
+
+ q.ring[q.tail%len(q.ring)] = n
+ q.tail++
+}
+
+// popLeft pops a node from the left of the queue. It panics if q is
+// empty.
+func (q *nodeQueue) popLeft() *Node {
+ if q.empty() {
+ panic("dequeue empty")
+ }
+ n := q.ring[q.head%len(q.ring)]
+ q.head++
+ return n
+}
+
+// NodeSet is a set of Nodes.
+type NodeSet map[*Node]struct{}
+
+// Has reports whether s contains n.
+func (s NodeSet) Has(n *Node) bool {
+ _, isPresent := s[n]
+ return isPresent
+}
+
+// Add adds n to s.
+func (s *NodeSet) Add(n *Node) {
+ if *s == nil {
+ *s = make(map[*Node]struct{})
+ }
+ (*s)[n] = struct{}{}
+}
+
+// Sorted returns s sorted according to less.
+func (s NodeSet) Sorted(less func(*Node, *Node) bool) []*Node {
+ var res []*Node
+ for n := range s {
+ res = append(res, n)
+ }
+ sort.Slice(res, func(i, j int) bool { return less(res[i], res[j]) })
+ return res
+}
diff --git a/src/cmd/compile/internal/gc/testdata/addressed_test.go b/src/cmd/compile/internal/gc/testdata/addressed_test.go
new file mode 100644
index 0000000..cdabf97
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/addressed_test.go
@@ -0,0 +1,210 @@
+// Copyright 2015 The Go Authors. 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"
+ "testing"
+)
+
+var output string
+
+func mypanic(t *testing.T, s string) {
+ t.Fatalf(s + "\n" + output)
+
+}
+
+func assertEqual(t *testing.T, x, y int) {
+ if x != y {
+ mypanic(t, fmt.Sprintf("assertEqual failed got %d, want %d", x, y))
+ }
+}
+
+func TestAddressed(t *testing.T) {
+ x := f1_ssa(2, 3)
+ output += fmt.Sprintln("*x is", *x)
+ output += fmt.Sprintln("Gratuitously use some stack")
+ output += fmt.Sprintln("*x is", *x)
+ assertEqual(t, *x, 9)
+
+ w := f3a_ssa(6)
+ output += fmt.Sprintln("*w is", *w)
+ output += fmt.Sprintln("Gratuitously use some stack")
+ output += fmt.Sprintln("*w is", *w)
+ assertEqual(t, *w, 6)
+
+ y := f3b_ssa(12)
+ output += fmt.Sprintln("*y.(*int) is", *y.(*int))
+ output += fmt.Sprintln("Gratuitously use some stack")
+ output += fmt.Sprintln("*y.(*int) is", *y.(*int))
+ assertEqual(t, *y.(*int), 12)
+
+ z := f3c_ssa(8)
+ output += fmt.Sprintln("*z.(*int) is", *z.(*int))
+ output += fmt.Sprintln("Gratuitously use some stack")
+ output += fmt.Sprintln("*z.(*int) is", *z.(*int))
+ assertEqual(t, *z.(*int), 8)
+
+ args(t)
+ test_autos(t)
+}
+
+//go:noinline
+func f1_ssa(x, y int) *int {
+ x = x*y + y
+ return &x
+}
+
+//go:noinline
+func f3a_ssa(x int) *int {
+ return &x
+}
+
+//go:noinline
+func f3b_ssa(x int) interface{} { // ./foo.go:15: internal error: f3b_ssa ~r1 (type interface {}) recorded as live on entry
+ return &x
+}
+
+//go:noinline
+func f3c_ssa(y int) interface{} {
+ x := y
+ return &x
+}
+
+type V struct {
+ p *V
+ w, x int64
+}
+
+func args(t *testing.T) {
+ v := V{p: nil, w: 1, x: 1}
+ a := V{p: &v, w: 2, x: 2}
+ b := V{p: &v, w: 0, x: 0}
+ i := v.args_ssa(a, b)
+ output += fmt.Sprintln("i=", i)
+ assertEqual(t, int(i), 2)
+}
+
+//go:noinline
+func (v V) args_ssa(a, b V) int64 {
+ if v.w == 0 {
+ return v.x
+ }
+ if v.w == 1 {
+ return a.x
+ }
+ if v.w == 2 {
+ return b.x
+ }
+ b.p.p = &a // v.p in caller = &a
+
+ return -1
+}
+
+func test_autos(t *testing.T) {
+ test(t, 11)
+ test(t, 12)
+ test(t, 13)
+ test(t, 21)
+ test(t, 22)
+ test(t, 23)
+ test(t, 31)
+ test(t, 32)
+}
+
+func test(t *testing.T, which int64) {
+ output += fmt.Sprintln("test", which)
+ v1 := V{w: 30, x: 3, p: nil}
+ v2, v3 := v1.autos_ssa(which, 10, 1, 20, 2)
+ if which != v2.val() {
+ output += fmt.Sprintln("Expected which=", which, "got v2.val()=", v2.val())
+ mypanic(t, "Failure of expected V value")
+ }
+ if v2.p.val() != v3.val() {
+ output += fmt.Sprintln("Expected v2.p.val()=", v2.p.val(), "got v3.val()=", v3.val())
+ mypanic(t, "Failure of expected V.p value")
+ }
+ if which != v3.p.p.p.p.p.p.p.val() {
+ output += fmt.Sprintln("Expected which=", which, "got v3.p.p.p.p.p.p.p.val()=", v3.p.p.p.p.p.p.p.val())
+ mypanic(t, "Failure of expected V.p value")
+ }
+}
+
+func (v V) val() int64 {
+ return v.w + v.x
+}
+
+// autos_ssa uses contents of v and parameters w1, w2, x1, x2
+// to initialize a bunch of locals, all of which have their
+// address taken to force heap allocation, and then based on
+// the value of which a pair of those locals are copied in
+// various ways to the two results y, and z, which are also
+// addressed. Which is expected to be one of 11-13, 21-23, 31, 32,
+// and y.val() should be equal to which and y.p.val() should
+// be equal to z.val(). Also, x(.p)**8 == x; that is, the
+// autos are all linked into a ring.
+//go:noinline
+func (v V) autos_ssa(which, w1, x1, w2, x2 int64) (y, z V) {
+ fill_ssa(v.w, v.x, &v, v.p) // gratuitous no-op to force addressing
+ var a, b, c, d, e, f, g, h V
+ fill_ssa(w1, x1, &a, &b)
+ fill_ssa(w1, x2, &b, &c)
+ fill_ssa(w1, v.x, &c, &d)
+ fill_ssa(w2, x1, &d, &e)
+ fill_ssa(w2, x2, &e, &f)
+ fill_ssa(w2, v.x, &f, &g)
+ fill_ssa(v.w, x1, &g, &h)
+ fill_ssa(v.w, x2, &h, &a)
+ switch which {
+ case 11:
+ y = a
+ z.getsI(&b)
+ case 12:
+ y.gets(&b)
+ z = c
+ case 13:
+ y.gets(&c)
+ z = d
+ case 21:
+ y.getsI(&d)
+ z.gets(&e)
+ case 22:
+ y = e
+ z = f
+ case 23:
+ y.gets(&f)
+ z.getsI(&g)
+ case 31:
+ y = g
+ z.gets(&h)
+ case 32:
+ y.getsI(&h)
+ z = a
+ default:
+
+ panic("")
+ }
+ return
+}
+
+// gets is an address-mentioning way of implementing
+// structure assignment.
+//go:noinline
+func (to *V) gets(from *V) {
+ *to = *from
+}
+
+// gets is an address-and-interface-mentioning way of
+// implementing structure assignment.
+//go:noinline
+func (to *V) getsI(from interface{}) {
+ *to = *from.(*V)
+}
+
+// fill_ssa initializes r with V{w:w, x:x, p:p}
+//go:noinline
+func fill_ssa(w, x int64, r, p *V) {
+ *r = V{w: w, x: x, p: p}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/append_test.go b/src/cmd/compile/internal/gc/testdata/append_test.go
new file mode 100644
index 0000000..6663ce7
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/append_test.go
@@ -0,0 +1,61 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// append_ssa.go tests append operations.
+package main
+
+import "testing"
+
+//go:noinline
+func appendOne_ssa(a []int, x int) []int {
+ return append(a, x)
+}
+
+//go:noinline
+func appendThree_ssa(a []int, x, y, z int) []int {
+ return append(a, x, y, z)
+}
+
+func eqBytes(a, b []int) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func expect(t *testing.T, got, want []int) {
+ if eqBytes(got, want) {
+ return
+ }
+ t.Errorf("expected %v, got %v\n", want, got)
+}
+
+func testAppend(t *testing.T) {
+ var store [7]int
+ a := store[:0]
+
+ a = appendOne_ssa(a, 1)
+ expect(t, a, []int{1})
+ a = appendThree_ssa(a, 2, 3, 4)
+ expect(t, a, []int{1, 2, 3, 4})
+ a = appendThree_ssa(a, 5, 6, 7)
+ expect(t, a, []int{1, 2, 3, 4, 5, 6, 7})
+ if &a[0] != &store[0] {
+ t.Errorf("unnecessary grow")
+ }
+ a = appendOne_ssa(a, 8)
+ expect(t, a, []int{1, 2, 3, 4, 5, 6, 7, 8})
+ if &a[0] == &store[0] {
+ t.Errorf("didn't grow")
+ }
+}
+
+func TestAppend(t *testing.T) {
+ testAppend(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/arithBoundary_test.go b/src/cmd/compile/internal/gc/testdata/arithBoundary_test.go
new file mode 100644
index 0000000..777b7cd
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/arithBoundary_test.go
@@ -0,0 +1,694 @@
+// Code generated by gen/arithBoundaryGen.go. DO NOT EDIT.
+
+package main
+
+import "testing"
+
+type utd64 struct {
+ a, b uint64
+ add, sub, mul, div, mod uint64
+}
+type itd64 struct {
+ a, b int64
+ add, sub, mul, div, mod int64
+}
+type utd32 struct {
+ a, b uint32
+ add, sub, mul, div, mod uint32
+}
+type itd32 struct {
+ a, b int32
+ add, sub, mul, div, mod int32
+}
+type utd16 struct {
+ a, b uint16
+ add, sub, mul, div, mod uint16
+}
+type itd16 struct {
+ a, b int16
+ add, sub, mul, div, mod int16
+}
+type utd8 struct {
+ a, b uint8
+ add, sub, mul, div, mod uint8
+}
+type itd8 struct {
+ a, b int8
+ add, sub, mul, div, mod int8
+}
+
+//go:noinline
+func add_uint64_ssa(a, b uint64) uint64 {
+ return a + b
+}
+
+//go:noinline
+func sub_uint64_ssa(a, b uint64) uint64 {
+ return a - b
+}
+
+//go:noinline
+func div_uint64_ssa(a, b uint64) uint64 {
+ return a / b
+}
+
+//go:noinline
+func mod_uint64_ssa(a, b uint64) uint64 {
+ return a % b
+}
+
+//go:noinline
+func mul_uint64_ssa(a, b uint64) uint64 {
+ return a * b
+}
+
+//go:noinline
+func add_int64_ssa(a, b int64) int64 {
+ return a + b
+}
+
+//go:noinline
+func sub_int64_ssa(a, b int64) int64 {
+ return a - b
+}
+
+//go:noinline
+func div_int64_ssa(a, b int64) int64 {
+ return a / b
+}
+
+//go:noinline
+func mod_int64_ssa(a, b int64) int64 {
+ return a % b
+}
+
+//go:noinline
+func mul_int64_ssa(a, b int64) int64 {
+ return a * b
+}
+
+//go:noinline
+func add_uint32_ssa(a, b uint32) uint32 {
+ return a + b
+}
+
+//go:noinline
+func sub_uint32_ssa(a, b uint32) uint32 {
+ return a - b
+}
+
+//go:noinline
+func div_uint32_ssa(a, b uint32) uint32 {
+ return a / b
+}
+
+//go:noinline
+func mod_uint32_ssa(a, b uint32) uint32 {
+ return a % b
+}
+
+//go:noinline
+func mul_uint32_ssa(a, b uint32) uint32 {
+ return a * b
+}
+
+//go:noinline
+func add_int32_ssa(a, b int32) int32 {
+ return a + b
+}
+
+//go:noinline
+func sub_int32_ssa(a, b int32) int32 {
+ return a - b
+}
+
+//go:noinline
+func div_int32_ssa(a, b int32) int32 {
+ return a / b
+}
+
+//go:noinline
+func mod_int32_ssa(a, b int32) int32 {
+ return a % b
+}
+
+//go:noinline
+func mul_int32_ssa(a, b int32) int32 {
+ return a * b
+}
+
+//go:noinline
+func add_uint16_ssa(a, b uint16) uint16 {
+ return a + b
+}
+
+//go:noinline
+func sub_uint16_ssa(a, b uint16) uint16 {
+ return a - b
+}
+
+//go:noinline
+func div_uint16_ssa(a, b uint16) uint16 {
+ return a / b
+}
+
+//go:noinline
+func mod_uint16_ssa(a, b uint16) uint16 {
+ return a % b
+}
+
+//go:noinline
+func mul_uint16_ssa(a, b uint16) uint16 {
+ return a * b
+}
+
+//go:noinline
+func add_int16_ssa(a, b int16) int16 {
+ return a + b
+}
+
+//go:noinline
+func sub_int16_ssa(a, b int16) int16 {
+ return a - b
+}
+
+//go:noinline
+func div_int16_ssa(a, b int16) int16 {
+ return a / b
+}
+
+//go:noinline
+func mod_int16_ssa(a, b int16) int16 {
+ return a % b
+}
+
+//go:noinline
+func mul_int16_ssa(a, b int16) int16 {
+ return a * b
+}
+
+//go:noinline
+func add_uint8_ssa(a, b uint8) uint8 {
+ return a + b
+}
+
+//go:noinline
+func sub_uint8_ssa(a, b uint8) uint8 {
+ return a - b
+}
+
+//go:noinline
+func div_uint8_ssa(a, b uint8) uint8 {
+ return a / b
+}
+
+//go:noinline
+func mod_uint8_ssa(a, b uint8) uint8 {
+ return a % b
+}
+
+//go:noinline
+func mul_uint8_ssa(a, b uint8) uint8 {
+ return a * b
+}
+
+//go:noinline
+func add_int8_ssa(a, b int8) int8 {
+ return a + b
+}
+
+//go:noinline
+func sub_int8_ssa(a, b int8) int8 {
+ return a - b
+}
+
+//go:noinline
+func div_int8_ssa(a, b int8) int8 {
+ return a / b
+}
+
+//go:noinline
+func mod_int8_ssa(a, b int8) int8 {
+ return a % b
+}
+
+//go:noinline
+func mul_int8_ssa(a, b int8) int8 {
+ return a * b
+}
+
+var uint64_data []utd64 = []utd64{utd64{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+ utd64{a: 0, b: 1, add: 1, sub: 18446744073709551615, mul: 0, div: 0, mod: 0},
+ utd64{a: 0, b: 4294967296, add: 4294967296, sub: 18446744069414584320, mul: 0, div: 0, mod: 0},
+ utd64{a: 0, b: 18446744073709551615, add: 18446744073709551615, sub: 1, mul: 0, div: 0, mod: 0},
+ utd64{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+ utd64{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ utd64{a: 1, b: 4294967296, add: 4294967297, sub: 18446744069414584321, mul: 4294967296, div: 0, mod: 1},
+ utd64{a: 1, b: 18446744073709551615, add: 0, sub: 2, mul: 18446744073709551615, div: 0, mod: 1},
+ utd64{a: 4294967296, b: 0, add: 4294967296, sub: 4294967296, mul: 0},
+ utd64{a: 4294967296, b: 1, add: 4294967297, sub: 4294967295, mul: 4294967296, div: 4294967296, mod: 0},
+ utd64{a: 4294967296, b: 4294967296, add: 8589934592, sub: 0, mul: 0, div: 1, mod: 0},
+ utd64{a: 4294967296, b: 18446744073709551615, add: 4294967295, sub: 4294967297, mul: 18446744069414584320, div: 0, mod: 4294967296},
+ utd64{a: 18446744073709551615, b: 0, add: 18446744073709551615, sub: 18446744073709551615, mul: 0},
+ utd64{a: 18446744073709551615, b: 1, add: 0, sub: 18446744073709551614, mul: 18446744073709551615, div: 18446744073709551615, mod: 0},
+ utd64{a: 18446744073709551615, b: 4294967296, add: 4294967295, sub: 18446744069414584319, mul: 18446744069414584320, div: 4294967295, mod: 4294967295},
+ utd64{a: 18446744073709551615, b: 18446744073709551615, add: 18446744073709551614, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var int64_data []itd64 = []itd64{itd64{a: -9223372036854775808, b: -9223372036854775808, add: 0, sub: 0, mul: 0, div: 1, mod: 0},
+ itd64{a: -9223372036854775808, b: -9223372036854775807, add: 1, sub: -1, mul: -9223372036854775808, div: 1, mod: -1},
+ itd64{a: -9223372036854775808, b: -4294967296, add: 9223372032559808512, sub: -9223372032559808512, mul: 0, div: 2147483648, mod: 0},
+ itd64{a: -9223372036854775808, b: -1, add: 9223372036854775807, sub: -9223372036854775807, mul: -9223372036854775808, div: -9223372036854775808, mod: 0},
+ itd64{a: -9223372036854775808, b: 0, add: -9223372036854775808, sub: -9223372036854775808, mul: 0},
+ itd64{a: -9223372036854775808, b: 1, add: -9223372036854775807, sub: 9223372036854775807, mul: -9223372036854775808, div: -9223372036854775808, mod: 0},
+ itd64{a: -9223372036854775808, b: 4294967296, add: -9223372032559808512, sub: 9223372032559808512, mul: 0, div: -2147483648, mod: 0},
+ itd64{a: -9223372036854775808, b: 9223372036854775806, add: -2, sub: 2, mul: 0, div: -1, mod: -2},
+ itd64{a: -9223372036854775808, b: 9223372036854775807, add: -1, sub: 1, mul: -9223372036854775808, div: -1, mod: -1},
+ itd64{a: -9223372036854775807, b: -9223372036854775808, add: 1, sub: 1, mul: -9223372036854775808, div: 0, mod: -9223372036854775807},
+ itd64{a: -9223372036854775807, b: -9223372036854775807, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd64{a: -9223372036854775807, b: -4294967296, add: 9223372032559808513, sub: -9223372032559808511, mul: -4294967296, div: 2147483647, mod: -4294967295},
+ itd64{a: -9223372036854775807, b: -1, add: -9223372036854775808, sub: -9223372036854775806, mul: 9223372036854775807, div: 9223372036854775807, mod: 0},
+ itd64{a: -9223372036854775807, b: 0, add: -9223372036854775807, sub: -9223372036854775807, mul: 0},
+ itd64{a: -9223372036854775807, b: 1, add: -9223372036854775806, sub: -9223372036854775808, mul: -9223372036854775807, div: -9223372036854775807, mod: 0},
+ itd64{a: -9223372036854775807, b: 4294967296, add: -9223372032559808511, sub: 9223372032559808513, mul: 4294967296, div: -2147483647, mod: -4294967295},
+ itd64{a: -9223372036854775807, b: 9223372036854775806, add: -1, sub: 3, mul: 9223372036854775806, div: -1, mod: -1},
+ itd64{a: -9223372036854775807, b: 9223372036854775807, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+ itd64{a: -4294967296, b: -9223372036854775808, add: 9223372032559808512, sub: 9223372032559808512, mul: 0, div: 0, mod: -4294967296},
+ itd64{a: -4294967296, b: -9223372036854775807, add: 9223372032559808513, sub: 9223372032559808511, mul: -4294967296, div: 0, mod: -4294967296},
+ itd64{a: -4294967296, b: -4294967296, add: -8589934592, sub: 0, mul: 0, div: 1, mod: 0},
+ itd64{a: -4294967296, b: -1, add: -4294967297, sub: -4294967295, mul: 4294967296, div: 4294967296, mod: 0},
+ itd64{a: -4294967296, b: 0, add: -4294967296, sub: -4294967296, mul: 0},
+ itd64{a: -4294967296, b: 1, add: -4294967295, sub: -4294967297, mul: -4294967296, div: -4294967296, mod: 0},
+ itd64{a: -4294967296, b: 4294967296, add: 0, sub: -8589934592, mul: 0, div: -1, mod: 0},
+ itd64{a: -4294967296, b: 9223372036854775806, add: 9223372032559808510, sub: 9223372032559808514, mul: 8589934592, div: 0, mod: -4294967296},
+ itd64{a: -4294967296, b: 9223372036854775807, add: 9223372032559808511, sub: 9223372032559808513, mul: 4294967296, div: 0, mod: -4294967296},
+ itd64{a: -1, b: -9223372036854775808, add: 9223372036854775807, sub: 9223372036854775807, mul: -9223372036854775808, div: 0, mod: -1},
+ itd64{a: -1, b: -9223372036854775807, add: -9223372036854775808, sub: 9223372036854775806, mul: 9223372036854775807, div: 0, mod: -1},
+ itd64{a: -1, b: -4294967296, add: -4294967297, sub: 4294967295, mul: 4294967296, div: 0, mod: -1},
+ itd64{a: -1, b: -1, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd64{a: -1, b: 0, add: -1, sub: -1, mul: 0},
+ itd64{a: -1, b: 1, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+ itd64{a: -1, b: 4294967296, add: 4294967295, sub: -4294967297, mul: -4294967296, div: 0, mod: -1},
+ itd64{a: -1, b: 9223372036854775806, add: 9223372036854775805, sub: -9223372036854775807, mul: -9223372036854775806, div: 0, mod: -1},
+ itd64{a: -1, b: 9223372036854775807, add: 9223372036854775806, sub: -9223372036854775808, mul: -9223372036854775807, div: 0, mod: -1},
+ itd64{a: 0, b: -9223372036854775808, add: -9223372036854775808, sub: -9223372036854775808, mul: 0, div: 0, mod: 0},
+ itd64{a: 0, b: -9223372036854775807, add: -9223372036854775807, sub: 9223372036854775807, mul: 0, div: 0, mod: 0},
+ itd64{a: 0, b: -4294967296, add: -4294967296, sub: 4294967296, mul: 0, div: 0, mod: 0},
+ itd64{a: 0, b: -1, add: -1, sub: 1, mul: 0, div: 0, mod: 0},
+ itd64{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+ itd64{a: 0, b: 1, add: 1, sub: -1, mul: 0, div: 0, mod: 0},
+ itd64{a: 0, b: 4294967296, add: 4294967296, sub: -4294967296, mul: 0, div: 0, mod: 0},
+ itd64{a: 0, b: 9223372036854775806, add: 9223372036854775806, sub: -9223372036854775806, mul: 0, div: 0, mod: 0},
+ itd64{a: 0, b: 9223372036854775807, add: 9223372036854775807, sub: -9223372036854775807, mul: 0, div: 0, mod: 0},
+ itd64{a: 1, b: -9223372036854775808, add: -9223372036854775807, sub: -9223372036854775807, mul: -9223372036854775808, div: 0, mod: 1},
+ itd64{a: 1, b: -9223372036854775807, add: -9223372036854775806, sub: -9223372036854775808, mul: -9223372036854775807, div: 0, mod: 1},
+ itd64{a: 1, b: -4294967296, add: -4294967295, sub: 4294967297, mul: -4294967296, div: 0, mod: 1},
+ itd64{a: 1, b: -1, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+ itd64{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+ itd64{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd64{a: 1, b: 4294967296, add: 4294967297, sub: -4294967295, mul: 4294967296, div: 0, mod: 1},
+ itd64{a: 1, b: 9223372036854775806, add: 9223372036854775807, sub: -9223372036854775805, mul: 9223372036854775806, div: 0, mod: 1},
+ itd64{a: 1, b: 9223372036854775807, add: -9223372036854775808, sub: -9223372036854775806, mul: 9223372036854775807, div: 0, mod: 1},
+ itd64{a: 4294967296, b: -9223372036854775808, add: -9223372032559808512, sub: -9223372032559808512, mul: 0, div: 0, mod: 4294967296},
+ itd64{a: 4294967296, b: -9223372036854775807, add: -9223372032559808511, sub: -9223372032559808513, mul: 4294967296, div: 0, mod: 4294967296},
+ itd64{a: 4294967296, b: -4294967296, add: 0, sub: 8589934592, mul: 0, div: -1, mod: 0},
+ itd64{a: 4294967296, b: -1, add: 4294967295, sub: 4294967297, mul: -4294967296, div: -4294967296, mod: 0},
+ itd64{a: 4294967296, b: 0, add: 4294967296, sub: 4294967296, mul: 0},
+ itd64{a: 4294967296, b: 1, add: 4294967297, sub: 4294967295, mul: 4294967296, div: 4294967296, mod: 0},
+ itd64{a: 4294967296, b: 4294967296, add: 8589934592, sub: 0, mul: 0, div: 1, mod: 0},
+ itd64{a: 4294967296, b: 9223372036854775806, add: -9223372032559808514, sub: -9223372032559808510, mul: -8589934592, div: 0, mod: 4294967296},
+ itd64{a: 4294967296, b: 9223372036854775807, add: -9223372032559808513, sub: -9223372032559808511, mul: -4294967296, div: 0, mod: 4294967296},
+ itd64{a: 9223372036854775806, b: -9223372036854775808, add: -2, sub: -2, mul: 0, div: 0, mod: 9223372036854775806},
+ itd64{a: 9223372036854775806, b: -9223372036854775807, add: -1, sub: -3, mul: 9223372036854775806, div: 0, mod: 9223372036854775806},
+ itd64{a: 9223372036854775806, b: -4294967296, add: 9223372032559808510, sub: -9223372032559808514, mul: 8589934592, div: -2147483647, mod: 4294967294},
+ itd64{a: 9223372036854775806, b: -1, add: 9223372036854775805, sub: 9223372036854775807, mul: -9223372036854775806, div: -9223372036854775806, mod: 0},
+ itd64{a: 9223372036854775806, b: 0, add: 9223372036854775806, sub: 9223372036854775806, mul: 0},
+ itd64{a: 9223372036854775806, b: 1, add: 9223372036854775807, sub: 9223372036854775805, mul: 9223372036854775806, div: 9223372036854775806, mod: 0},
+ itd64{a: 9223372036854775806, b: 4294967296, add: -9223372032559808514, sub: 9223372032559808510, mul: -8589934592, div: 2147483647, mod: 4294967294},
+ itd64{a: 9223372036854775806, b: 9223372036854775806, add: -4, sub: 0, mul: 4, div: 1, mod: 0},
+ itd64{a: 9223372036854775806, b: 9223372036854775807, add: -3, sub: -1, mul: -9223372036854775806, div: 0, mod: 9223372036854775806},
+ itd64{a: 9223372036854775807, b: -9223372036854775808, add: -1, sub: -1, mul: -9223372036854775808, div: 0, mod: 9223372036854775807},
+ itd64{a: 9223372036854775807, b: -9223372036854775807, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+ itd64{a: 9223372036854775807, b: -4294967296, add: 9223372032559808511, sub: -9223372032559808513, mul: 4294967296, div: -2147483647, mod: 4294967295},
+ itd64{a: 9223372036854775807, b: -1, add: 9223372036854775806, sub: -9223372036854775808, mul: -9223372036854775807, div: -9223372036854775807, mod: 0},
+ itd64{a: 9223372036854775807, b: 0, add: 9223372036854775807, sub: 9223372036854775807, mul: 0},
+ itd64{a: 9223372036854775807, b: 1, add: -9223372036854775808, sub: 9223372036854775806, mul: 9223372036854775807, div: 9223372036854775807, mod: 0},
+ itd64{a: 9223372036854775807, b: 4294967296, add: -9223372032559808513, sub: 9223372032559808511, mul: -4294967296, div: 2147483647, mod: 4294967295},
+ itd64{a: 9223372036854775807, b: 9223372036854775806, add: -3, sub: 1, mul: -9223372036854775806, div: 1, mod: 1},
+ itd64{a: 9223372036854775807, b: 9223372036854775807, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var uint32_data []utd32 = []utd32{utd32{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+ utd32{a: 0, b: 1, add: 1, sub: 4294967295, mul: 0, div: 0, mod: 0},
+ utd32{a: 0, b: 4294967295, add: 4294967295, sub: 1, mul: 0, div: 0, mod: 0},
+ utd32{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+ utd32{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ utd32{a: 1, b: 4294967295, add: 0, sub: 2, mul: 4294967295, div: 0, mod: 1},
+ utd32{a: 4294967295, b: 0, add: 4294967295, sub: 4294967295, mul: 0},
+ utd32{a: 4294967295, b: 1, add: 0, sub: 4294967294, mul: 4294967295, div: 4294967295, mod: 0},
+ utd32{a: 4294967295, b: 4294967295, add: 4294967294, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var int32_data []itd32 = []itd32{itd32{a: -2147483648, b: -2147483648, add: 0, sub: 0, mul: 0, div: 1, mod: 0},
+ itd32{a: -2147483648, b: -2147483647, add: 1, sub: -1, mul: -2147483648, div: 1, mod: -1},
+ itd32{a: -2147483648, b: -1, add: 2147483647, sub: -2147483647, mul: -2147483648, div: -2147483648, mod: 0},
+ itd32{a: -2147483648, b: 0, add: -2147483648, sub: -2147483648, mul: 0},
+ itd32{a: -2147483648, b: 1, add: -2147483647, sub: 2147483647, mul: -2147483648, div: -2147483648, mod: 0},
+ itd32{a: -2147483648, b: 2147483647, add: -1, sub: 1, mul: -2147483648, div: -1, mod: -1},
+ itd32{a: -2147483647, b: -2147483648, add: 1, sub: 1, mul: -2147483648, div: 0, mod: -2147483647},
+ itd32{a: -2147483647, b: -2147483647, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd32{a: -2147483647, b: -1, add: -2147483648, sub: -2147483646, mul: 2147483647, div: 2147483647, mod: 0},
+ itd32{a: -2147483647, b: 0, add: -2147483647, sub: -2147483647, mul: 0},
+ itd32{a: -2147483647, b: 1, add: -2147483646, sub: -2147483648, mul: -2147483647, div: -2147483647, mod: 0},
+ itd32{a: -2147483647, b: 2147483647, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+ itd32{a: -1, b: -2147483648, add: 2147483647, sub: 2147483647, mul: -2147483648, div: 0, mod: -1},
+ itd32{a: -1, b: -2147483647, add: -2147483648, sub: 2147483646, mul: 2147483647, div: 0, mod: -1},
+ itd32{a: -1, b: -1, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd32{a: -1, b: 0, add: -1, sub: -1, mul: 0},
+ itd32{a: -1, b: 1, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+ itd32{a: -1, b: 2147483647, add: 2147483646, sub: -2147483648, mul: -2147483647, div: 0, mod: -1},
+ itd32{a: 0, b: -2147483648, add: -2147483648, sub: -2147483648, mul: 0, div: 0, mod: 0},
+ itd32{a: 0, b: -2147483647, add: -2147483647, sub: 2147483647, mul: 0, div: 0, mod: 0},
+ itd32{a: 0, b: -1, add: -1, sub: 1, mul: 0, div: 0, mod: 0},
+ itd32{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+ itd32{a: 0, b: 1, add: 1, sub: -1, mul: 0, div: 0, mod: 0},
+ itd32{a: 0, b: 2147483647, add: 2147483647, sub: -2147483647, mul: 0, div: 0, mod: 0},
+ itd32{a: 1, b: -2147483648, add: -2147483647, sub: -2147483647, mul: -2147483648, div: 0, mod: 1},
+ itd32{a: 1, b: -2147483647, add: -2147483646, sub: -2147483648, mul: -2147483647, div: 0, mod: 1},
+ itd32{a: 1, b: -1, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+ itd32{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+ itd32{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd32{a: 1, b: 2147483647, add: -2147483648, sub: -2147483646, mul: 2147483647, div: 0, mod: 1},
+ itd32{a: 2147483647, b: -2147483648, add: -1, sub: -1, mul: -2147483648, div: 0, mod: 2147483647},
+ itd32{a: 2147483647, b: -2147483647, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+ itd32{a: 2147483647, b: -1, add: 2147483646, sub: -2147483648, mul: -2147483647, div: -2147483647, mod: 0},
+ itd32{a: 2147483647, b: 0, add: 2147483647, sub: 2147483647, mul: 0},
+ itd32{a: 2147483647, b: 1, add: -2147483648, sub: 2147483646, mul: 2147483647, div: 2147483647, mod: 0},
+ itd32{a: 2147483647, b: 2147483647, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var uint16_data []utd16 = []utd16{utd16{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+ utd16{a: 0, b: 1, add: 1, sub: 65535, mul: 0, div: 0, mod: 0},
+ utd16{a: 0, b: 65535, add: 65535, sub: 1, mul: 0, div: 0, mod: 0},
+ utd16{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+ utd16{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ utd16{a: 1, b: 65535, add: 0, sub: 2, mul: 65535, div: 0, mod: 1},
+ utd16{a: 65535, b: 0, add: 65535, sub: 65535, mul: 0},
+ utd16{a: 65535, b: 1, add: 0, sub: 65534, mul: 65535, div: 65535, mod: 0},
+ utd16{a: 65535, b: 65535, add: 65534, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var int16_data []itd16 = []itd16{itd16{a: -32768, b: -32768, add: 0, sub: 0, mul: 0, div: 1, mod: 0},
+ itd16{a: -32768, b: -32767, add: 1, sub: -1, mul: -32768, div: 1, mod: -1},
+ itd16{a: -32768, b: -1, add: 32767, sub: -32767, mul: -32768, div: -32768, mod: 0},
+ itd16{a: -32768, b: 0, add: -32768, sub: -32768, mul: 0},
+ itd16{a: -32768, b: 1, add: -32767, sub: 32767, mul: -32768, div: -32768, mod: 0},
+ itd16{a: -32768, b: 32766, add: -2, sub: 2, mul: 0, div: -1, mod: -2},
+ itd16{a: -32768, b: 32767, add: -1, sub: 1, mul: -32768, div: -1, mod: -1},
+ itd16{a: -32767, b: -32768, add: 1, sub: 1, mul: -32768, div: 0, mod: -32767},
+ itd16{a: -32767, b: -32767, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd16{a: -32767, b: -1, add: -32768, sub: -32766, mul: 32767, div: 32767, mod: 0},
+ itd16{a: -32767, b: 0, add: -32767, sub: -32767, mul: 0},
+ itd16{a: -32767, b: 1, add: -32766, sub: -32768, mul: -32767, div: -32767, mod: 0},
+ itd16{a: -32767, b: 32766, add: -1, sub: 3, mul: 32766, div: -1, mod: -1},
+ itd16{a: -32767, b: 32767, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+ itd16{a: -1, b: -32768, add: 32767, sub: 32767, mul: -32768, div: 0, mod: -1},
+ itd16{a: -1, b: -32767, add: -32768, sub: 32766, mul: 32767, div: 0, mod: -1},
+ itd16{a: -1, b: -1, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd16{a: -1, b: 0, add: -1, sub: -1, mul: 0},
+ itd16{a: -1, b: 1, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+ itd16{a: -1, b: 32766, add: 32765, sub: -32767, mul: -32766, div: 0, mod: -1},
+ itd16{a: -1, b: 32767, add: 32766, sub: -32768, mul: -32767, div: 0, mod: -1},
+ itd16{a: 0, b: -32768, add: -32768, sub: -32768, mul: 0, div: 0, mod: 0},
+ itd16{a: 0, b: -32767, add: -32767, sub: 32767, mul: 0, div: 0, mod: 0},
+ itd16{a: 0, b: -1, add: -1, sub: 1, mul: 0, div: 0, mod: 0},
+ itd16{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+ itd16{a: 0, b: 1, add: 1, sub: -1, mul: 0, div: 0, mod: 0},
+ itd16{a: 0, b: 32766, add: 32766, sub: -32766, mul: 0, div: 0, mod: 0},
+ itd16{a: 0, b: 32767, add: 32767, sub: -32767, mul: 0, div: 0, mod: 0},
+ itd16{a: 1, b: -32768, add: -32767, sub: -32767, mul: -32768, div: 0, mod: 1},
+ itd16{a: 1, b: -32767, add: -32766, sub: -32768, mul: -32767, div: 0, mod: 1},
+ itd16{a: 1, b: -1, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+ itd16{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+ itd16{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd16{a: 1, b: 32766, add: 32767, sub: -32765, mul: 32766, div: 0, mod: 1},
+ itd16{a: 1, b: 32767, add: -32768, sub: -32766, mul: 32767, div: 0, mod: 1},
+ itd16{a: 32766, b: -32768, add: -2, sub: -2, mul: 0, div: 0, mod: 32766},
+ itd16{a: 32766, b: -32767, add: -1, sub: -3, mul: 32766, div: 0, mod: 32766},
+ itd16{a: 32766, b: -1, add: 32765, sub: 32767, mul: -32766, div: -32766, mod: 0},
+ itd16{a: 32766, b: 0, add: 32766, sub: 32766, mul: 0},
+ itd16{a: 32766, b: 1, add: 32767, sub: 32765, mul: 32766, div: 32766, mod: 0},
+ itd16{a: 32766, b: 32766, add: -4, sub: 0, mul: 4, div: 1, mod: 0},
+ itd16{a: 32766, b: 32767, add: -3, sub: -1, mul: -32766, div: 0, mod: 32766},
+ itd16{a: 32767, b: -32768, add: -1, sub: -1, mul: -32768, div: 0, mod: 32767},
+ itd16{a: 32767, b: -32767, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+ itd16{a: 32767, b: -1, add: 32766, sub: -32768, mul: -32767, div: -32767, mod: 0},
+ itd16{a: 32767, b: 0, add: 32767, sub: 32767, mul: 0},
+ itd16{a: 32767, b: 1, add: -32768, sub: 32766, mul: 32767, div: 32767, mod: 0},
+ itd16{a: 32767, b: 32766, add: -3, sub: 1, mul: -32766, div: 1, mod: 1},
+ itd16{a: 32767, b: 32767, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var uint8_data []utd8 = []utd8{utd8{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+ utd8{a: 0, b: 1, add: 1, sub: 255, mul: 0, div: 0, mod: 0},
+ utd8{a: 0, b: 255, add: 255, sub: 1, mul: 0, div: 0, mod: 0},
+ utd8{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+ utd8{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ utd8{a: 1, b: 255, add: 0, sub: 2, mul: 255, div: 0, mod: 1},
+ utd8{a: 255, b: 0, add: 255, sub: 255, mul: 0},
+ utd8{a: 255, b: 1, add: 0, sub: 254, mul: 255, div: 255, mod: 0},
+ utd8{a: 255, b: 255, add: 254, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var int8_data []itd8 = []itd8{itd8{a: -128, b: -128, add: 0, sub: 0, mul: 0, div: 1, mod: 0},
+ itd8{a: -128, b: -127, add: 1, sub: -1, mul: -128, div: 1, mod: -1},
+ itd8{a: -128, b: -1, add: 127, sub: -127, mul: -128, div: -128, mod: 0},
+ itd8{a: -128, b: 0, add: -128, sub: -128, mul: 0},
+ itd8{a: -128, b: 1, add: -127, sub: 127, mul: -128, div: -128, mod: 0},
+ itd8{a: -128, b: 126, add: -2, sub: 2, mul: 0, div: -1, mod: -2},
+ itd8{a: -128, b: 127, add: -1, sub: 1, mul: -128, div: -1, mod: -1},
+ itd8{a: -127, b: -128, add: 1, sub: 1, mul: -128, div: 0, mod: -127},
+ itd8{a: -127, b: -127, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd8{a: -127, b: -1, add: -128, sub: -126, mul: 127, div: 127, mod: 0},
+ itd8{a: -127, b: 0, add: -127, sub: -127, mul: 0},
+ itd8{a: -127, b: 1, add: -126, sub: -128, mul: -127, div: -127, mod: 0},
+ itd8{a: -127, b: 126, add: -1, sub: 3, mul: 126, div: -1, mod: -1},
+ itd8{a: -127, b: 127, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+ itd8{a: -1, b: -128, add: 127, sub: 127, mul: -128, div: 0, mod: -1},
+ itd8{a: -1, b: -127, add: -128, sub: 126, mul: 127, div: 0, mod: -1},
+ itd8{a: -1, b: -1, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd8{a: -1, b: 0, add: -1, sub: -1, mul: 0},
+ itd8{a: -1, b: 1, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+ itd8{a: -1, b: 126, add: 125, sub: -127, mul: -126, div: 0, mod: -1},
+ itd8{a: -1, b: 127, add: 126, sub: -128, mul: -127, div: 0, mod: -1},
+ itd8{a: 0, b: -128, add: -128, sub: -128, mul: 0, div: 0, mod: 0},
+ itd8{a: 0, b: -127, add: -127, sub: 127, mul: 0, div: 0, mod: 0},
+ itd8{a: 0, b: -1, add: -1, sub: 1, mul: 0, div: 0, mod: 0},
+ itd8{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+ itd8{a: 0, b: 1, add: 1, sub: -1, mul: 0, div: 0, mod: 0},
+ itd8{a: 0, b: 126, add: 126, sub: -126, mul: 0, div: 0, mod: 0},
+ itd8{a: 0, b: 127, add: 127, sub: -127, mul: 0, div: 0, mod: 0},
+ itd8{a: 1, b: -128, add: -127, sub: -127, mul: -128, div: 0, mod: 1},
+ itd8{a: 1, b: -127, add: -126, sub: -128, mul: -127, div: 0, mod: 1},
+ itd8{a: 1, b: -1, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+ itd8{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+ itd8{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+ itd8{a: 1, b: 126, add: 127, sub: -125, mul: 126, div: 0, mod: 1},
+ itd8{a: 1, b: 127, add: -128, sub: -126, mul: 127, div: 0, mod: 1},
+ itd8{a: 126, b: -128, add: -2, sub: -2, mul: 0, div: 0, mod: 126},
+ itd8{a: 126, b: -127, add: -1, sub: -3, mul: 126, div: 0, mod: 126},
+ itd8{a: 126, b: -1, add: 125, sub: 127, mul: -126, div: -126, mod: 0},
+ itd8{a: 126, b: 0, add: 126, sub: 126, mul: 0},
+ itd8{a: 126, b: 1, add: 127, sub: 125, mul: 126, div: 126, mod: 0},
+ itd8{a: 126, b: 126, add: -4, sub: 0, mul: 4, div: 1, mod: 0},
+ itd8{a: 126, b: 127, add: -3, sub: -1, mul: -126, div: 0, mod: 126},
+ itd8{a: 127, b: -128, add: -1, sub: -1, mul: -128, div: 0, mod: 127},
+ itd8{a: 127, b: -127, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+ itd8{a: 127, b: -1, add: 126, sub: -128, mul: -127, div: -127, mod: 0},
+ itd8{a: 127, b: 0, add: 127, sub: 127, mul: 0},
+ itd8{a: 127, b: 1, add: -128, sub: 126, mul: 127, div: 127, mod: 0},
+ itd8{a: 127, b: 126, add: -3, sub: 1, mul: -126, div: 1, mod: 1},
+ itd8{a: 127, b: 127, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+}
+
+//TestArithmeticBoundary tests boundary results for arithmetic operations.
+func TestArithmeticBoundary(t *testing.T) {
+
+ for _, v := range uint64_data {
+ if got := add_uint64_ssa(v.a, v.b); got != v.add {
+ t.Errorf("add_uint64 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+ }
+ if got := sub_uint64_ssa(v.a, v.b); got != v.sub {
+ t.Errorf("sub_uint64 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+ }
+ if v.b != 0 {
+ if got := div_uint64_ssa(v.a, v.b); got != v.div {
+ t.Errorf("div_uint64 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+ }
+
+ }
+ if v.b != 0 {
+ if got := mod_uint64_ssa(v.a, v.b); got != v.mod {
+ t.Errorf("mod_uint64 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+ }
+
+ }
+ if got := mul_uint64_ssa(v.a, v.b); got != v.mul {
+ t.Errorf("mul_uint64 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+ }
+ }
+ for _, v := range int64_data {
+ if got := add_int64_ssa(v.a, v.b); got != v.add {
+ t.Errorf("add_int64 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+ }
+ if got := sub_int64_ssa(v.a, v.b); got != v.sub {
+ t.Errorf("sub_int64 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+ }
+ if v.b != 0 {
+ if got := div_int64_ssa(v.a, v.b); got != v.div {
+ t.Errorf("div_int64 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+ }
+
+ }
+ if v.b != 0 {
+ if got := mod_int64_ssa(v.a, v.b); got != v.mod {
+ t.Errorf("mod_int64 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+ }
+
+ }
+ if got := mul_int64_ssa(v.a, v.b); got != v.mul {
+ t.Errorf("mul_int64 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+ }
+ }
+ for _, v := range uint32_data {
+ if got := add_uint32_ssa(v.a, v.b); got != v.add {
+ t.Errorf("add_uint32 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+ }
+ if got := sub_uint32_ssa(v.a, v.b); got != v.sub {
+ t.Errorf("sub_uint32 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+ }
+ if v.b != 0 {
+ if got := div_uint32_ssa(v.a, v.b); got != v.div {
+ t.Errorf("div_uint32 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+ }
+
+ }
+ if v.b != 0 {
+ if got := mod_uint32_ssa(v.a, v.b); got != v.mod {
+ t.Errorf("mod_uint32 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+ }
+
+ }
+ if got := mul_uint32_ssa(v.a, v.b); got != v.mul {
+ t.Errorf("mul_uint32 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+ }
+ }
+ for _, v := range int32_data {
+ if got := add_int32_ssa(v.a, v.b); got != v.add {
+ t.Errorf("add_int32 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+ }
+ if got := sub_int32_ssa(v.a, v.b); got != v.sub {
+ t.Errorf("sub_int32 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+ }
+ if v.b != 0 {
+ if got := div_int32_ssa(v.a, v.b); got != v.div {
+ t.Errorf("div_int32 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+ }
+
+ }
+ if v.b != 0 {
+ if got := mod_int32_ssa(v.a, v.b); got != v.mod {
+ t.Errorf("mod_int32 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+ }
+
+ }
+ if got := mul_int32_ssa(v.a, v.b); got != v.mul {
+ t.Errorf("mul_int32 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+ }
+ }
+ for _, v := range uint16_data {
+ if got := add_uint16_ssa(v.a, v.b); got != v.add {
+ t.Errorf("add_uint16 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+ }
+ if got := sub_uint16_ssa(v.a, v.b); got != v.sub {
+ t.Errorf("sub_uint16 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+ }
+ if v.b != 0 {
+ if got := div_uint16_ssa(v.a, v.b); got != v.div {
+ t.Errorf("div_uint16 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+ }
+
+ }
+ if v.b != 0 {
+ if got := mod_uint16_ssa(v.a, v.b); got != v.mod {
+ t.Errorf("mod_uint16 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+ }
+
+ }
+ if got := mul_uint16_ssa(v.a, v.b); got != v.mul {
+ t.Errorf("mul_uint16 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+ }
+ }
+ for _, v := range int16_data {
+ if got := add_int16_ssa(v.a, v.b); got != v.add {
+ t.Errorf("add_int16 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+ }
+ if got := sub_int16_ssa(v.a, v.b); got != v.sub {
+ t.Errorf("sub_int16 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+ }
+ if v.b != 0 {
+ if got := div_int16_ssa(v.a, v.b); got != v.div {
+ t.Errorf("div_int16 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+ }
+
+ }
+ if v.b != 0 {
+ if got := mod_int16_ssa(v.a, v.b); got != v.mod {
+ t.Errorf("mod_int16 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+ }
+
+ }
+ if got := mul_int16_ssa(v.a, v.b); got != v.mul {
+ t.Errorf("mul_int16 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+ }
+ }
+ for _, v := range uint8_data {
+ if got := add_uint8_ssa(v.a, v.b); got != v.add {
+ t.Errorf("add_uint8 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+ }
+ if got := sub_uint8_ssa(v.a, v.b); got != v.sub {
+ t.Errorf("sub_uint8 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+ }
+ if v.b != 0 {
+ if got := div_uint8_ssa(v.a, v.b); got != v.div {
+ t.Errorf("div_uint8 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+ }
+
+ }
+ if v.b != 0 {
+ if got := mod_uint8_ssa(v.a, v.b); got != v.mod {
+ t.Errorf("mod_uint8 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+ }
+
+ }
+ if got := mul_uint8_ssa(v.a, v.b); got != v.mul {
+ t.Errorf("mul_uint8 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+ }
+ }
+ for _, v := range int8_data {
+ if got := add_int8_ssa(v.a, v.b); got != v.add {
+ t.Errorf("add_int8 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+ }
+ if got := sub_int8_ssa(v.a, v.b); got != v.sub {
+ t.Errorf("sub_int8 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+ }
+ if v.b != 0 {
+ if got := div_int8_ssa(v.a, v.b); got != v.div {
+ t.Errorf("div_int8 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+ }
+
+ }
+ if v.b != 0 {
+ if got := mod_int8_ssa(v.a, v.b); got != v.mod {
+ t.Errorf("mod_int8 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+ }
+
+ }
+ if got := mul_int8_ssa(v.a, v.b); got != v.mul {
+ t.Errorf("mul_int8 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/arithConst_test.go b/src/cmd/compile/internal/gc/testdata/arithConst_test.go
new file mode 100644
index 0000000..9f5ac61
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/arithConst_test.go
@@ -0,0 +1,9570 @@
+// Code generated by gen/arithConstGen.go. DO NOT EDIT.
+
+package main
+
+import "testing"
+
+//go:noinline
+func add_uint64_0(a uint64) uint64 { return a + 0 }
+
+//go:noinline
+func add_0_uint64(a uint64) uint64 { return 0 + a }
+
+//go:noinline
+func add_uint64_1(a uint64) uint64 { return a + 1 }
+
+//go:noinline
+func add_1_uint64(a uint64) uint64 { return 1 + a }
+
+//go:noinline
+func add_uint64_4294967296(a uint64) uint64 { return a + 4294967296 }
+
+//go:noinline
+func add_4294967296_uint64(a uint64) uint64 { return 4294967296 + a }
+
+//go:noinline
+func add_uint64_9223372036854775808(a uint64) uint64 { return a + 9223372036854775808 }
+
+//go:noinline
+func add_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 + a }
+
+//go:noinline
+func add_uint64_18446744073709551615(a uint64) uint64 { return a + 18446744073709551615 }
+
+//go:noinline
+func add_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 + a }
+
+//go:noinline
+func sub_uint64_0(a uint64) uint64 { return a - 0 }
+
+//go:noinline
+func sub_0_uint64(a uint64) uint64 { return 0 - a }
+
+//go:noinline
+func sub_uint64_1(a uint64) uint64 { return a - 1 }
+
+//go:noinline
+func sub_1_uint64(a uint64) uint64 { return 1 - a }
+
+//go:noinline
+func sub_uint64_4294967296(a uint64) uint64 { return a - 4294967296 }
+
+//go:noinline
+func sub_4294967296_uint64(a uint64) uint64 { return 4294967296 - a }
+
+//go:noinline
+func sub_uint64_9223372036854775808(a uint64) uint64 { return a - 9223372036854775808 }
+
+//go:noinline
+func sub_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 - a }
+
+//go:noinline
+func sub_uint64_18446744073709551615(a uint64) uint64 { return a - 18446744073709551615 }
+
+//go:noinline
+func sub_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 - a }
+
+//go:noinline
+func div_0_uint64(a uint64) uint64 { return 0 / a }
+
+//go:noinline
+func div_uint64_1(a uint64) uint64 { return a / 1 }
+
+//go:noinline
+func div_1_uint64(a uint64) uint64 { return 1 / a }
+
+//go:noinline
+func div_uint64_4294967296(a uint64) uint64 { return a / 4294967296 }
+
+//go:noinline
+func div_4294967296_uint64(a uint64) uint64 { return 4294967296 / a }
+
+//go:noinline
+func div_uint64_9223372036854775808(a uint64) uint64 { return a / 9223372036854775808 }
+
+//go:noinline
+func div_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 / a }
+
+//go:noinline
+func div_uint64_18446744073709551615(a uint64) uint64 { return a / 18446744073709551615 }
+
+//go:noinline
+func div_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 / a }
+
+//go:noinline
+func mul_uint64_0(a uint64) uint64 { return a * 0 }
+
+//go:noinline
+func mul_0_uint64(a uint64) uint64 { return 0 * a }
+
+//go:noinline
+func mul_uint64_1(a uint64) uint64 { return a * 1 }
+
+//go:noinline
+func mul_1_uint64(a uint64) uint64 { return 1 * a }
+
+//go:noinline
+func mul_uint64_4294967296(a uint64) uint64 { return a * 4294967296 }
+
+//go:noinline
+func mul_4294967296_uint64(a uint64) uint64 { return 4294967296 * a }
+
+//go:noinline
+func mul_uint64_9223372036854775808(a uint64) uint64 { return a * 9223372036854775808 }
+
+//go:noinline
+func mul_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 * a }
+
+//go:noinline
+func mul_uint64_18446744073709551615(a uint64) uint64 { return a * 18446744073709551615 }
+
+//go:noinline
+func mul_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 * a }
+
+//go:noinline
+func lsh_uint64_0(a uint64) uint64 { return a << 0 }
+
+//go:noinline
+func lsh_0_uint64(a uint64) uint64 { return 0 << a }
+
+//go:noinline
+func lsh_uint64_1(a uint64) uint64 { return a << 1 }
+
+//go:noinline
+func lsh_1_uint64(a uint64) uint64 { return 1 << a }
+
+//go:noinline
+func lsh_uint64_4294967296(a uint64) uint64 { return a << uint64(4294967296) }
+
+//go:noinline
+func lsh_4294967296_uint64(a uint64) uint64 { return 4294967296 << a }
+
+//go:noinline
+func lsh_uint64_9223372036854775808(a uint64) uint64 { return a << uint64(9223372036854775808) }
+
+//go:noinline
+func lsh_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 << a }
+
+//go:noinline
+func lsh_uint64_18446744073709551615(a uint64) uint64 { return a << uint64(18446744073709551615) }
+
+//go:noinline
+func lsh_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 << a }
+
+//go:noinline
+func rsh_uint64_0(a uint64) uint64 { return a >> 0 }
+
+//go:noinline
+func rsh_0_uint64(a uint64) uint64 { return 0 >> a }
+
+//go:noinline
+func rsh_uint64_1(a uint64) uint64 { return a >> 1 }
+
+//go:noinline
+func rsh_1_uint64(a uint64) uint64 { return 1 >> a }
+
+//go:noinline
+func rsh_uint64_4294967296(a uint64) uint64 { return a >> uint64(4294967296) }
+
+//go:noinline
+func rsh_4294967296_uint64(a uint64) uint64 { return 4294967296 >> a }
+
+//go:noinline
+func rsh_uint64_9223372036854775808(a uint64) uint64 { return a >> uint64(9223372036854775808) }
+
+//go:noinline
+func rsh_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 >> a }
+
+//go:noinline
+func rsh_uint64_18446744073709551615(a uint64) uint64 { return a >> uint64(18446744073709551615) }
+
+//go:noinline
+func rsh_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 >> a }
+
+//go:noinline
+func mod_0_uint64(a uint64) uint64 { return 0 % a }
+
+//go:noinline
+func mod_uint64_1(a uint64) uint64 { return a % 1 }
+
+//go:noinline
+func mod_1_uint64(a uint64) uint64 { return 1 % a }
+
+//go:noinline
+func mod_uint64_4294967296(a uint64) uint64 { return a % 4294967296 }
+
+//go:noinline
+func mod_4294967296_uint64(a uint64) uint64 { return 4294967296 % a }
+
+//go:noinline
+func mod_uint64_9223372036854775808(a uint64) uint64 { return a % 9223372036854775808 }
+
+//go:noinline
+func mod_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 % a }
+
+//go:noinline
+func mod_uint64_18446744073709551615(a uint64) uint64 { return a % 18446744073709551615 }
+
+//go:noinline
+func mod_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 % a }
+
+//go:noinline
+func and_uint64_0(a uint64) uint64 { return a & 0 }
+
+//go:noinline
+func and_0_uint64(a uint64) uint64 { return 0 & a }
+
+//go:noinline
+func and_uint64_1(a uint64) uint64 { return a & 1 }
+
+//go:noinline
+func and_1_uint64(a uint64) uint64 { return 1 & a }
+
+//go:noinline
+func and_uint64_4294967296(a uint64) uint64 { return a & 4294967296 }
+
+//go:noinline
+func and_4294967296_uint64(a uint64) uint64 { return 4294967296 & a }
+
+//go:noinline
+func and_uint64_9223372036854775808(a uint64) uint64 { return a & 9223372036854775808 }
+
+//go:noinline
+func and_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 & a }
+
+//go:noinline
+func and_uint64_18446744073709551615(a uint64) uint64 { return a & 18446744073709551615 }
+
+//go:noinline
+func and_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 & a }
+
+//go:noinline
+func or_uint64_0(a uint64) uint64 { return a | 0 }
+
+//go:noinline
+func or_0_uint64(a uint64) uint64 { return 0 | a }
+
+//go:noinline
+func or_uint64_1(a uint64) uint64 { return a | 1 }
+
+//go:noinline
+func or_1_uint64(a uint64) uint64 { return 1 | a }
+
+//go:noinline
+func or_uint64_4294967296(a uint64) uint64 { return a | 4294967296 }
+
+//go:noinline
+func or_4294967296_uint64(a uint64) uint64 { return 4294967296 | a }
+
+//go:noinline
+func or_uint64_9223372036854775808(a uint64) uint64 { return a | 9223372036854775808 }
+
+//go:noinline
+func or_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 | a }
+
+//go:noinline
+func or_uint64_18446744073709551615(a uint64) uint64 { return a | 18446744073709551615 }
+
+//go:noinline
+func or_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 | a }
+
+//go:noinline
+func xor_uint64_0(a uint64) uint64 { return a ^ 0 }
+
+//go:noinline
+func xor_0_uint64(a uint64) uint64 { return 0 ^ a }
+
+//go:noinline
+func xor_uint64_1(a uint64) uint64 { return a ^ 1 }
+
+//go:noinline
+func xor_1_uint64(a uint64) uint64 { return 1 ^ a }
+
+//go:noinline
+func xor_uint64_4294967296(a uint64) uint64 { return a ^ 4294967296 }
+
+//go:noinline
+func xor_4294967296_uint64(a uint64) uint64 { return 4294967296 ^ a }
+
+//go:noinline
+func xor_uint64_9223372036854775808(a uint64) uint64 { return a ^ 9223372036854775808 }
+
+//go:noinline
+func xor_9223372036854775808_uint64(a uint64) uint64 { return 9223372036854775808 ^ a }
+
+//go:noinline
+func xor_uint64_18446744073709551615(a uint64) uint64 { return a ^ 18446744073709551615 }
+
+//go:noinline
+func xor_18446744073709551615_uint64(a uint64) uint64 { return 18446744073709551615 ^ a }
+
+//go:noinline
+func mul_uint64_3(a uint64) uint64 { return a * 3 }
+
+//go:noinline
+func mul_3_uint64(a uint64) uint64 { return 3 * a }
+
+//go:noinline
+func mul_uint64_5(a uint64) uint64 { return a * 5 }
+
+//go:noinline
+func mul_5_uint64(a uint64) uint64 { return 5 * a }
+
+//go:noinline
+func mul_uint64_7(a uint64) uint64 { return a * 7 }
+
+//go:noinline
+func mul_7_uint64(a uint64) uint64 { return 7 * a }
+
+//go:noinline
+func mul_uint64_9(a uint64) uint64 { return a * 9 }
+
+//go:noinline
+func mul_9_uint64(a uint64) uint64 { return 9 * a }
+
+//go:noinline
+func mul_uint64_10(a uint64) uint64 { return a * 10 }
+
+//go:noinline
+func mul_10_uint64(a uint64) uint64 { return 10 * a }
+
+//go:noinline
+func mul_uint64_11(a uint64) uint64 { return a * 11 }
+
+//go:noinline
+func mul_11_uint64(a uint64) uint64 { return 11 * a }
+
+//go:noinline
+func mul_uint64_13(a uint64) uint64 { return a * 13 }
+
+//go:noinline
+func mul_13_uint64(a uint64) uint64 { return 13 * a }
+
+//go:noinline
+func mul_uint64_19(a uint64) uint64 { return a * 19 }
+
+//go:noinline
+func mul_19_uint64(a uint64) uint64 { return 19 * a }
+
+//go:noinline
+func mul_uint64_21(a uint64) uint64 { return a * 21 }
+
+//go:noinline
+func mul_21_uint64(a uint64) uint64 { return 21 * a }
+
+//go:noinline
+func mul_uint64_25(a uint64) uint64 { return a * 25 }
+
+//go:noinline
+func mul_25_uint64(a uint64) uint64 { return 25 * a }
+
+//go:noinline
+func mul_uint64_27(a uint64) uint64 { return a * 27 }
+
+//go:noinline
+func mul_27_uint64(a uint64) uint64 { return 27 * a }
+
+//go:noinline
+func mul_uint64_37(a uint64) uint64 { return a * 37 }
+
+//go:noinline
+func mul_37_uint64(a uint64) uint64 { return 37 * a }
+
+//go:noinline
+func mul_uint64_41(a uint64) uint64 { return a * 41 }
+
+//go:noinline
+func mul_41_uint64(a uint64) uint64 { return 41 * a }
+
+//go:noinline
+func mul_uint64_45(a uint64) uint64 { return a * 45 }
+
+//go:noinline
+func mul_45_uint64(a uint64) uint64 { return 45 * a }
+
+//go:noinline
+func mul_uint64_73(a uint64) uint64 { return a * 73 }
+
+//go:noinline
+func mul_73_uint64(a uint64) uint64 { return 73 * a }
+
+//go:noinline
+func mul_uint64_81(a uint64) uint64 { return a * 81 }
+
+//go:noinline
+func mul_81_uint64(a uint64) uint64 { return 81 * a }
+
+//go:noinline
+func add_int64_Neg9223372036854775808(a int64) int64 { return a + -9223372036854775808 }
+
+//go:noinline
+func add_Neg9223372036854775808_int64(a int64) int64 { return -9223372036854775808 + a }
+
+//go:noinline
+func add_int64_Neg9223372036854775807(a int64) int64 { return a + -9223372036854775807 }
+
+//go:noinline
+func add_Neg9223372036854775807_int64(a int64) int64 { return -9223372036854775807 + a }
+
+//go:noinline
+func add_int64_Neg4294967296(a int64) int64 { return a + -4294967296 }
+
+//go:noinline
+func add_Neg4294967296_int64(a int64) int64 { return -4294967296 + a }
+
+//go:noinline
+func add_int64_Neg1(a int64) int64 { return a + -1 }
+
+//go:noinline
+func add_Neg1_int64(a int64) int64 { return -1 + a }
+
+//go:noinline
+func add_int64_0(a int64) int64 { return a + 0 }
+
+//go:noinline
+func add_0_int64(a int64) int64 { return 0 + a }
+
+//go:noinline
+func add_int64_1(a int64) int64 { return a + 1 }
+
+//go:noinline
+func add_1_int64(a int64) int64 { return 1 + a }
+
+//go:noinline
+func add_int64_4294967296(a int64) int64 { return a + 4294967296 }
+
+//go:noinline
+func add_4294967296_int64(a int64) int64 { return 4294967296 + a }
+
+//go:noinline
+func add_int64_9223372036854775806(a int64) int64 { return a + 9223372036854775806 }
+
+//go:noinline
+func add_9223372036854775806_int64(a int64) int64 { return 9223372036854775806 + a }
+
+//go:noinline
+func add_int64_9223372036854775807(a int64) int64 { return a + 9223372036854775807 }
+
+//go:noinline
+func add_9223372036854775807_int64(a int64) int64 { return 9223372036854775807 + a }
+
+//go:noinline
+func sub_int64_Neg9223372036854775808(a int64) int64 { return a - -9223372036854775808 }
+
+//go:noinline
+func sub_Neg9223372036854775808_int64(a int64) int64 { return -9223372036854775808 - a }
+
+//go:noinline
+func sub_int64_Neg9223372036854775807(a int64) int64 { return a - -9223372036854775807 }
+
+//go:noinline
+func sub_Neg9223372036854775807_int64(a int64) int64 { return -9223372036854775807 - a }
+
+//go:noinline
+func sub_int64_Neg4294967296(a int64) int64 { return a - -4294967296 }
+
+//go:noinline
+func sub_Neg4294967296_int64(a int64) int64 { return -4294967296 - a }
+
+//go:noinline
+func sub_int64_Neg1(a int64) int64 { return a - -1 }
+
+//go:noinline
+func sub_Neg1_int64(a int64) int64 { return -1 - a }
+
+//go:noinline
+func sub_int64_0(a int64) int64 { return a - 0 }
+
+//go:noinline
+func sub_0_int64(a int64) int64 { return 0 - a }
+
+//go:noinline
+func sub_int64_1(a int64) int64 { return a - 1 }
+
+//go:noinline
+func sub_1_int64(a int64) int64 { return 1 - a }
+
+//go:noinline
+func sub_int64_4294967296(a int64) int64 { return a - 4294967296 }
+
+//go:noinline
+func sub_4294967296_int64(a int64) int64 { return 4294967296 - a }
+
+//go:noinline
+func sub_int64_9223372036854775806(a int64) int64 { return a - 9223372036854775806 }
+
+//go:noinline
+func sub_9223372036854775806_int64(a int64) int64 { return 9223372036854775806 - a }
+
+//go:noinline
+func sub_int64_9223372036854775807(a int64) int64 { return a - 9223372036854775807 }
+
+//go:noinline
+func sub_9223372036854775807_int64(a int64) int64 { return 9223372036854775807 - a }
+
+//go:noinline
+func div_int64_Neg9223372036854775808(a int64) int64 { return a / -9223372036854775808 }
+
+//go:noinline
+func div_Neg9223372036854775808_int64(a int64) int64 { return -9223372036854775808 / a }
+
+//go:noinline
+func div_int64_Neg9223372036854775807(a int64) int64 { return a / -9223372036854775807 }
+
+//go:noinline
+func div_Neg9223372036854775807_int64(a int64) int64 { return -9223372036854775807 / a }
+
+//go:noinline
+func div_int64_Neg4294967296(a int64) int64 { return a / -4294967296 }
+
+//go:noinline
+func div_Neg4294967296_int64(a int64) int64 { return -4294967296 / a }
+
+//go:noinline
+func div_int64_Neg1(a int64) int64 { return a / -1 }
+
+//go:noinline
+func div_Neg1_int64(a int64) int64 { return -1 / a }
+
+//go:noinline
+func div_0_int64(a int64) int64 { return 0 / a }
+
+//go:noinline
+func div_int64_1(a int64) int64 { return a / 1 }
+
+//go:noinline
+func div_1_int64(a int64) int64 { return 1 / a }
+
+//go:noinline
+func div_int64_4294967296(a int64) int64 { return a / 4294967296 }
+
+//go:noinline
+func div_4294967296_int64(a int64) int64 { return 4294967296 / a }
+
+//go:noinline
+func div_int64_9223372036854775806(a int64) int64 { return a / 9223372036854775806 }
+
+//go:noinline
+func div_9223372036854775806_int64(a int64) int64 { return 9223372036854775806 / a }
+
+//go:noinline
+func div_int64_9223372036854775807(a int64) int64 { return a / 9223372036854775807 }
+
+//go:noinline
+func div_9223372036854775807_int64(a int64) int64 { return 9223372036854775807 / a }
+
+//go:noinline
+func mul_int64_Neg9223372036854775808(a int64) int64 { return a * -9223372036854775808 }
+
+//go:noinline
+func mul_Neg9223372036854775808_int64(a int64) int64 { return -9223372036854775808 * a }
+
+//go:noinline
+func mul_int64_Neg9223372036854775807(a int64) int64 { return a * -9223372036854775807 }
+
+//go:noinline
+func mul_Neg9223372036854775807_int64(a int64) int64 { return -9223372036854775807 * a }
+
+//go:noinline
+func mul_int64_Neg4294967296(a int64) int64 { return a * -4294967296 }
+
+//go:noinline
+func mul_Neg4294967296_int64(a int64) int64 { return -4294967296 * a }
+
+//go:noinline
+func mul_int64_Neg1(a int64) int64 { return a * -1 }
+
+//go:noinline
+func mul_Neg1_int64(a int64) int64 { return -1 * a }
+
+//go:noinline
+func mul_int64_0(a int64) int64 { return a * 0 }
+
+//go:noinline
+func mul_0_int64(a int64) int64 { return 0 * a }
+
+//go:noinline
+func mul_int64_1(a int64) int64 { return a * 1 }
+
+//go:noinline
+func mul_1_int64(a int64) int64 { return 1 * a }
+
+//go:noinline
+func mul_int64_4294967296(a int64) int64 { return a * 4294967296 }
+
+//go:noinline
+func mul_4294967296_int64(a int64) int64 { return 4294967296 * a }
+
+//go:noinline
+func mul_int64_9223372036854775806(a int64) int64 { return a * 9223372036854775806 }
+
+//go:noinline
+func mul_9223372036854775806_int64(a int64) int64 { return 9223372036854775806 * a }
+
+//go:noinline
+func mul_int64_9223372036854775807(a int64) int64 { return a * 9223372036854775807 }
+
+//go:noinline
+func mul_9223372036854775807_int64(a int64) int64 { return 9223372036854775807 * a }
+
+//go:noinline
+func mod_int64_Neg9223372036854775808(a int64) int64 { return a % -9223372036854775808 }
+
+//go:noinline
+func mod_Neg9223372036854775808_int64(a int64) int64 { return -9223372036854775808 % a }
+
+//go:noinline
+func mod_int64_Neg9223372036854775807(a int64) int64 { return a % -9223372036854775807 }
+
+//go:noinline
+func mod_Neg9223372036854775807_int64(a int64) int64 { return -9223372036854775807 % a }
+
+//go:noinline
+func mod_int64_Neg4294967296(a int64) int64 { return a % -4294967296 }
+
+//go:noinline
+func mod_Neg4294967296_int64(a int64) int64 { return -4294967296 % a }
+
+//go:noinline
+func mod_int64_Neg1(a int64) int64 { return a % -1 }
+
+//go:noinline
+func mod_Neg1_int64(a int64) int64 { return -1 % a }
+
+//go:noinline
+func mod_0_int64(a int64) int64 { return 0 % a }
+
+//go:noinline
+func mod_int64_1(a int64) int64 { return a % 1 }
+
+//go:noinline
+func mod_1_int64(a int64) int64 { return 1 % a }
+
+//go:noinline
+func mod_int64_4294967296(a int64) int64 { return a % 4294967296 }
+
+//go:noinline
+func mod_4294967296_int64(a int64) int64 { return 4294967296 % a }
+
+//go:noinline
+func mod_int64_9223372036854775806(a int64) int64 { return a % 9223372036854775806 }
+
+//go:noinline
+func mod_9223372036854775806_int64(a int64) int64 { return 9223372036854775806 % a }
+
+//go:noinline
+func mod_int64_9223372036854775807(a int64) int64 { return a % 9223372036854775807 }
+
+//go:noinline
+func mod_9223372036854775807_int64(a int64) int64 { return 9223372036854775807 % a }
+
+//go:noinline
+func and_int64_Neg9223372036854775808(a int64) int64 { return a & -9223372036854775808 }
+
+//go:noinline
+func and_Neg9223372036854775808_int64(a int64) int64 { return -9223372036854775808 & a }
+
+//go:noinline
+func and_int64_Neg9223372036854775807(a int64) int64 { return a & -9223372036854775807 }
+
+//go:noinline
+func and_Neg9223372036854775807_int64(a int64) int64 { return -9223372036854775807 & a }
+
+//go:noinline
+func and_int64_Neg4294967296(a int64) int64 { return a & -4294967296 }
+
+//go:noinline
+func and_Neg4294967296_int64(a int64) int64 { return -4294967296 & a }
+
+//go:noinline
+func and_int64_Neg1(a int64) int64 { return a & -1 }
+
+//go:noinline
+func and_Neg1_int64(a int64) int64 { return -1 & a }
+
+//go:noinline
+func and_int64_0(a int64) int64 { return a & 0 }
+
+//go:noinline
+func and_0_int64(a int64) int64 { return 0 & a }
+
+//go:noinline
+func and_int64_1(a int64) int64 { return a & 1 }
+
+//go:noinline
+func and_1_int64(a int64) int64 { return 1 & a }
+
+//go:noinline
+func and_int64_4294967296(a int64) int64 { return a & 4294967296 }
+
+//go:noinline
+func and_4294967296_int64(a int64) int64 { return 4294967296 & a }
+
+//go:noinline
+func and_int64_9223372036854775806(a int64) int64 { return a & 9223372036854775806 }
+
+//go:noinline
+func and_9223372036854775806_int64(a int64) int64 { return 9223372036854775806 & a }
+
+//go:noinline
+func and_int64_9223372036854775807(a int64) int64 { return a & 9223372036854775807 }
+
+//go:noinline
+func and_9223372036854775807_int64(a int64) int64 { return 9223372036854775807 & a }
+
+//go:noinline
+func or_int64_Neg9223372036854775808(a int64) int64 { return a | -9223372036854775808 }
+
+//go:noinline
+func or_Neg9223372036854775808_int64(a int64) int64 { return -9223372036854775808 | a }
+
+//go:noinline
+func or_int64_Neg9223372036854775807(a int64) int64 { return a | -9223372036854775807 }
+
+//go:noinline
+func or_Neg9223372036854775807_int64(a int64) int64 { return -9223372036854775807 | a }
+
+//go:noinline
+func or_int64_Neg4294967296(a int64) int64 { return a | -4294967296 }
+
+//go:noinline
+func or_Neg4294967296_int64(a int64) int64 { return -4294967296 | a }
+
+//go:noinline
+func or_int64_Neg1(a int64) int64 { return a | -1 }
+
+//go:noinline
+func or_Neg1_int64(a int64) int64 { return -1 | a }
+
+//go:noinline
+func or_int64_0(a int64) int64 { return a | 0 }
+
+//go:noinline
+func or_0_int64(a int64) int64 { return 0 | a }
+
+//go:noinline
+func or_int64_1(a int64) int64 { return a | 1 }
+
+//go:noinline
+func or_1_int64(a int64) int64 { return 1 | a }
+
+//go:noinline
+func or_int64_4294967296(a int64) int64 { return a | 4294967296 }
+
+//go:noinline
+func or_4294967296_int64(a int64) int64 { return 4294967296 | a }
+
+//go:noinline
+func or_int64_9223372036854775806(a int64) int64 { return a | 9223372036854775806 }
+
+//go:noinline
+func or_9223372036854775806_int64(a int64) int64 { return 9223372036854775806 | a }
+
+//go:noinline
+func or_int64_9223372036854775807(a int64) int64 { return a | 9223372036854775807 }
+
+//go:noinline
+func or_9223372036854775807_int64(a int64) int64 { return 9223372036854775807 | a }
+
+//go:noinline
+func xor_int64_Neg9223372036854775808(a int64) int64 { return a ^ -9223372036854775808 }
+
+//go:noinline
+func xor_Neg9223372036854775808_int64(a int64) int64 { return -9223372036854775808 ^ a }
+
+//go:noinline
+func xor_int64_Neg9223372036854775807(a int64) int64 { return a ^ -9223372036854775807 }
+
+//go:noinline
+func xor_Neg9223372036854775807_int64(a int64) int64 { return -9223372036854775807 ^ a }
+
+//go:noinline
+func xor_int64_Neg4294967296(a int64) int64 { return a ^ -4294967296 }
+
+//go:noinline
+func xor_Neg4294967296_int64(a int64) int64 { return -4294967296 ^ a }
+
+//go:noinline
+func xor_int64_Neg1(a int64) int64 { return a ^ -1 }
+
+//go:noinline
+func xor_Neg1_int64(a int64) int64 { return -1 ^ a }
+
+//go:noinline
+func xor_int64_0(a int64) int64 { return a ^ 0 }
+
+//go:noinline
+func xor_0_int64(a int64) int64 { return 0 ^ a }
+
+//go:noinline
+func xor_int64_1(a int64) int64 { return a ^ 1 }
+
+//go:noinline
+func xor_1_int64(a int64) int64 { return 1 ^ a }
+
+//go:noinline
+func xor_int64_4294967296(a int64) int64 { return a ^ 4294967296 }
+
+//go:noinline
+func xor_4294967296_int64(a int64) int64 { return 4294967296 ^ a }
+
+//go:noinline
+func xor_int64_9223372036854775806(a int64) int64 { return a ^ 9223372036854775806 }
+
+//go:noinline
+func xor_9223372036854775806_int64(a int64) int64 { return 9223372036854775806 ^ a }
+
+//go:noinline
+func xor_int64_9223372036854775807(a int64) int64 { return a ^ 9223372036854775807 }
+
+//go:noinline
+func xor_9223372036854775807_int64(a int64) int64 { return 9223372036854775807 ^ a }
+
+//go:noinline
+func mul_int64_Neg9(a int64) int64 { return a * -9 }
+
+//go:noinline
+func mul_Neg9_int64(a int64) int64 { return -9 * a }
+
+//go:noinline
+func mul_int64_Neg5(a int64) int64 { return a * -5 }
+
+//go:noinline
+func mul_Neg5_int64(a int64) int64 { return -5 * a }
+
+//go:noinline
+func mul_int64_Neg3(a int64) int64 { return a * -3 }
+
+//go:noinline
+func mul_Neg3_int64(a int64) int64 { return -3 * a }
+
+//go:noinline
+func mul_int64_3(a int64) int64 { return a * 3 }
+
+//go:noinline
+func mul_3_int64(a int64) int64 { return 3 * a }
+
+//go:noinline
+func mul_int64_5(a int64) int64 { return a * 5 }
+
+//go:noinline
+func mul_5_int64(a int64) int64 { return 5 * a }
+
+//go:noinline
+func mul_int64_7(a int64) int64 { return a * 7 }
+
+//go:noinline
+func mul_7_int64(a int64) int64 { return 7 * a }
+
+//go:noinline
+func mul_int64_9(a int64) int64 { return a * 9 }
+
+//go:noinline
+func mul_9_int64(a int64) int64 { return 9 * a }
+
+//go:noinline
+func mul_int64_10(a int64) int64 { return a * 10 }
+
+//go:noinline
+func mul_10_int64(a int64) int64 { return 10 * a }
+
+//go:noinline
+func mul_int64_11(a int64) int64 { return a * 11 }
+
+//go:noinline
+func mul_11_int64(a int64) int64 { return 11 * a }
+
+//go:noinline
+func mul_int64_13(a int64) int64 { return a * 13 }
+
+//go:noinline
+func mul_13_int64(a int64) int64 { return 13 * a }
+
+//go:noinline
+func mul_int64_19(a int64) int64 { return a * 19 }
+
+//go:noinline
+func mul_19_int64(a int64) int64 { return 19 * a }
+
+//go:noinline
+func mul_int64_21(a int64) int64 { return a * 21 }
+
+//go:noinline
+func mul_21_int64(a int64) int64 { return 21 * a }
+
+//go:noinline
+func mul_int64_25(a int64) int64 { return a * 25 }
+
+//go:noinline
+func mul_25_int64(a int64) int64 { return 25 * a }
+
+//go:noinline
+func mul_int64_27(a int64) int64 { return a * 27 }
+
+//go:noinline
+func mul_27_int64(a int64) int64 { return 27 * a }
+
+//go:noinline
+func mul_int64_37(a int64) int64 { return a * 37 }
+
+//go:noinline
+func mul_37_int64(a int64) int64 { return 37 * a }
+
+//go:noinline
+func mul_int64_41(a int64) int64 { return a * 41 }
+
+//go:noinline
+func mul_41_int64(a int64) int64 { return 41 * a }
+
+//go:noinline
+func mul_int64_45(a int64) int64 { return a * 45 }
+
+//go:noinline
+func mul_45_int64(a int64) int64 { return 45 * a }
+
+//go:noinline
+func mul_int64_73(a int64) int64 { return a * 73 }
+
+//go:noinline
+func mul_73_int64(a int64) int64 { return 73 * a }
+
+//go:noinline
+func mul_int64_81(a int64) int64 { return a * 81 }
+
+//go:noinline
+func mul_81_int64(a int64) int64 { return 81 * a }
+
+//go:noinline
+func add_uint32_0(a uint32) uint32 { return a + 0 }
+
+//go:noinline
+func add_0_uint32(a uint32) uint32 { return 0 + a }
+
+//go:noinline
+func add_uint32_1(a uint32) uint32 { return a + 1 }
+
+//go:noinline
+func add_1_uint32(a uint32) uint32 { return 1 + a }
+
+//go:noinline
+func add_uint32_4294967295(a uint32) uint32 { return a + 4294967295 }
+
+//go:noinline
+func add_4294967295_uint32(a uint32) uint32 { return 4294967295 + a }
+
+//go:noinline
+func sub_uint32_0(a uint32) uint32 { return a - 0 }
+
+//go:noinline
+func sub_0_uint32(a uint32) uint32 { return 0 - a }
+
+//go:noinline
+func sub_uint32_1(a uint32) uint32 { return a - 1 }
+
+//go:noinline
+func sub_1_uint32(a uint32) uint32 { return 1 - a }
+
+//go:noinline
+func sub_uint32_4294967295(a uint32) uint32 { return a - 4294967295 }
+
+//go:noinline
+func sub_4294967295_uint32(a uint32) uint32 { return 4294967295 - a }
+
+//go:noinline
+func div_0_uint32(a uint32) uint32 { return 0 / a }
+
+//go:noinline
+func div_uint32_1(a uint32) uint32 { return a / 1 }
+
+//go:noinline
+func div_1_uint32(a uint32) uint32 { return 1 / a }
+
+//go:noinline
+func div_uint32_4294967295(a uint32) uint32 { return a / 4294967295 }
+
+//go:noinline
+func div_4294967295_uint32(a uint32) uint32 { return 4294967295 / a }
+
+//go:noinline
+func mul_uint32_0(a uint32) uint32 { return a * 0 }
+
+//go:noinline
+func mul_0_uint32(a uint32) uint32 { return 0 * a }
+
+//go:noinline
+func mul_uint32_1(a uint32) uint32 { return a * 1 }
+
+//go:noinline
+func mul_1_uint32(a uint32) uint32 { return 1 * a }
+
+//go:noinline
+func mul_uint32_4294967295(a uint32) uint32 { return a * 4294967295 }
+
+//go:noinline
+func mul_4294967295_uint32(a uint32) uint32 { return 4294967295 * a }
+
+//go:noinline
+func lsh_uint32_0(a uint32) uint32 { return a << 0 }
+
+//go:noinline
+func lsh_0_uint32(a uint32) uint32 { return 0 << a }
+
+//go:noinline
+func lsh_uint32_1(a uint32) uint32 { return a << 1 }
+
+//go:noinline
+func lsh_1_uint32(a uint32) uint32 { return 1 << a }
+
+//go:noinline
+func lsh_uint32_4294967295(a uint32) uint32 { return a << 4294967295 }
+
+//go:noinline
+func lsh_4294967295_uint32(a uint32) uint32 { return 4294967295 << a }
+
+//go:noinline
+func rsh_uint32_0(a uint32) uint32 { return a >> 0 }
+
+//go:noinline
+func rsh_0_uint32(a uint32) uint32 { return 0 >> a }
+
+//go:noinline
+func rsh_uint32_1(a uint32) uint32 { return a >> 1 }
+
+//go:noinline
+func rsh_1_uint32(a uint32) uint32 { return 1 >> a }
+
+//go:noinline
+func rsh_uint32_4294967295(a uint32) uint32 { return a >> 4294967295 }
+
+//go:noinline
+func rsh_4294967295_uint32(a uint32) uint32 { return 4294967295 >> a }
+
+//go:noinline
+func mod_0_uint32(a uint32) uint32 { return 0 % a }
+
+//go:noinline
+func mod_uint32_1(a uint32) uint32 { return a % 1 }
+
+//go:noinline
+func mod_1_uint32(a uint32) uint32 { return 1 % a }
+
+//go:noinline
+func mod_uint32_4294967295(a uint32) uint32 { return a % 4294967295 }
+
+//go:noinline
+func mod_4294967295_uint32(a uint32) uint32 { return 4294967295 % a }
+
+//go:noinline
+func and_uint32_0(a uint32) uint32 { return a & 0 }
+
+//go:noinline
+func and_0_uint32(a uint32) uint32 { return 0 & a }
+
+//go:noinline
+func and_uint32_1(a uint32) uint32 { return a & 1 }
+
+//go:noinline
+func and_1_uint32(a uint32) uint32 { return 1 & a }
+
+//go:noinline
+func and_uint32_4294967295(a uint32) uint32 { return a & 4294967295 }
+
+//go:noinline
+func and_4294967295_uint32(a uint32) uint32 { return 4294967295 & a }
+
+//go:noinline
+func or_uint32_0(a uint32) uint32 { return a | 0 }
+
+//go:noinline
+func or_0_uint32(a uint32) uint32 { return 0 | a }
+
+//go:noinline
+func or_uint32_1(a uint32) uint32 { return a | 1 }
+
+//go:noinline
+func or_1_uint32(a uint32) uint32 { return 1 | a }
+
+//go:noinline
+func or_uint32_4294967295(a uint32) uint32 { return a | 4294967295 }
+
+//go:noinline
+func or_4294967295_uint32(a uint32) uint32 { return 4294967295 | a }
+
+//go:noinline
+func xor_uint32_0(a uint32) uint32 { return a ^ 0 }
+
+//go:noinline
+func xor_0_uint32(a uint32) uint32 { return 0 ^ a }
+
+//go:noinline
+func xor_uint32_1(a uint32) uint32 { return a ^ 1 }
+
+//go:noinline
+func xor_1_uint32(a uint32) uint32 { return 1 ^ a }
+
+//go:noinline
+func xor_uint32_4294967295(a uint32) uint32 { return a ^ 4294967295 }
+
+//go:noinline
+func xor_4294967295_uint32(a uint32) uint32 { return 4294967295 ^ a }
+
+//go:noinline
+func mul_uint32_3(a uint32) uint32 { return a * 3 }
+
+//go:noinline
+func mul_3_uint32(a uint32) uint32 { return 3 * a }
+
+//go:noinline
+func mul_uint32_5(a uint32) uint32 { return a * 5 }
+
+//go:noinline
+func mul_5_uint32(a uint32) uint32 { return 5 * a }
+
+//go:noinline
+func mul_uint32_7(a uint32) uint32 { return a * 7 }
+
+//go:noinline
+func mul_7_uint32(a uint32) uint32 { return 7 * a }
+
+//go:noinline
+func mul_uint32_9(a uint32) uint32 { return a * 9 }
+
+//go:noinline
+func mul_9_uint32(a uint32) uint32 { return 9 * a }
+
+//go:noinline
+func mul_uint32_10(a uint32) uint32 { return a * 10 }
+
+//go:noinline
+func mul_10_uint32(a uint32) uint32 { return 10 * a }
+
+//go:noinline
+func mul_uint32_11(a uint32) uint32 { return a * 11 }
+
+//go:noinline
+func mul_11_uint32(a uint32) uint32 { return 11 * a }
+
+//go:noinline
+func mul_uint32_13(a uint32) uint32 { return a * 13 }
+
+//go:noinline
+func mul_13_uint32(a uint32) uint32 { return 13 * a }
+
+//go:noinline
+func mul_uint32_19(a uint32) uint32 { return a * 19 }
+
+//go:noinline
+func mul_19_uint32(a uint32) uint32 { return 19 * a }
+
+//go:noinline
+func mul_uint32_21(a uint32) uint32 { return a * 21 }
+
+//go:noinline
+func mul_21_uint32(a uint32) uint32 { return 21 * a }
+
+//go:noinline
+func mul_uint32_25(a uint32) uint32 { return a * 25 }
+
+//go:noinline
+func mul_25_uint32(a uint32) uint32 { return 25 * a }
+
+//go:noinline
+func mul_uint32_27(a uint32) uint32 { return a * 27 }
+
+//go:noinline
+func mul_27_uint32(a uint32) uint32 { return 27 * a }
+
+//go:noinline
+func mul_uint32_37(a uint32) uint32 { return a * 37 }
+
+//go:noinline
+func mul_37_uint32(a uint32) uint32 { return 37 * a }
+
+//go:noinline
+func mul_uint32_41(a uint32) uint32 { return a * 41 }
+
+//go:noinline
+func mul_41_uint32(a uint32) uint32 { return 41 * a }
+
+//go:noinline
+func mul_uint32_45(a uint32) uint32 { return a * 45 }
+
+//go:noinline
+func mul_45_uint32(a uint32) uint32 { return 45 * a }
+
+//go:noinline
+func mul_uint32_73(a uint32) uint32 { return a * 73 }
+
+//go:noinline
+func mul_73_uint32(a uint32) uint32 { return 73 * a }
+
+//go:noinline
+func mul_uint32_81(a uint32) uint32 { return a * 81 }
+
+//go:noinline
+func mul_81_uint32(a uint32) uint32 { return 81 * a }
+
+//go:noinline
+func add_int32_Neg2147483648(a int32) int32 { return a + -2147483648 }
+
+//go:noinline
+func add_Neg2147483648_int32(a int32) int32 { return -2147483648 + a }
+
+//go:noinline
+func add_int32_Neg2147483647(a int32) int32 { return a + -2147483647 }
+
+//go:noinline
+func add_Neg2147483647_int32(a int32) int32 { return -2147483647 + a }
+
+//go:noinline
+func add_int32_Neg1(a int32) int32 { return a + -1 }
+
+//go:noinline
+func add_Neg1_int32(a int32) int32 { return -1 + a }
+
+//go:noinline
+func add_int32_0(a int32) int32 { return a + 0 }
+
+//go:noinline
+func add_0_int32(a int32) int32 { return 0 + a }
+
+//go:noinline
+func add_int32_1(a int32) int32 { return a + 1 }
+
+//go:noinline
+func add_1_int32(a int32) int32 { return 1 + a }
+
+//go:noinline
+func add_int32_2147483647(a int32) int32 { return a + 2147483647 }
+
+//go:noinline
+func add_2147483647_int32(a int32) int32 { return 2147483647 + a }
+
+//go:noinline
+func sub_int32_Neg2147483648(a int32) int32 { return a - -2147483648 }
+
+//go:noinline
+func sub_Neg2147483648_int32(a int32) int32 { return -2147483648 - a }
+
+//go:noinline
+func sub_int32_Neg2147483647(a int32) int32 { return a - -2147483647 }
+
+//go:noinline
+func sub_Neg2147483647_int32(a int32) int32 { return -2147483647 - a }
+
+//go:noinline
+func sub_int32_Neg1(a int32) int32 { return a - -1 }
+
+//go:noinline
+func sub_Neg1_int32(a int32) int32 { return -1 - a }
+
+//go:noinline
+func sub_int32_0(a int32) int32 { return a - 0 }
+
+//go:noinline
+func sub_0_int32(a int32) int32 { return 0 - a }
+
+//go:noinline
+func sub_int32_1(a int32) int32 { return a - 1 }
+
+//go:noinline
+func sub_1_int32(a int32) int32 { return 1 - a }
+
+//go:noinline
+func sub_int32_2147483647(a int32) int32 { return a - 2147483647 }
+
+//go:noinline
+func sub_2147483647_int32(a int32) int32 { return 2147483647 - a }
+
+//go:noinline
+func div_int32_Neg2147483648(a int32) int32 { return a / -2147483648 }
+
+//go:noinline
+func div_Neg2147483648_int32(a int32) int32 { return -2147483648 / a }
+
+//go:noinline
+func div_int32_Neg2147483647(a int32) int32 { return a / -2147483647 }
+
+//go:noinline
+func div_Neg2147483647_int32(a int32) int32 { return -2147483647 / a }
+
+//go:noinline
+func div_int32_Neg1(a int32) int32 { return a / -1 }
+
+//go:noinline
+func div_Neg1_int32(a int32) int32 { return -1 / a }
+
+//go:noinline
+func div_0_int32(a int32) int32 { return 0 / a }
+
+//go:noinline
+func div_int32_1(a int32) int32 { return a / 1 }
+
+//go:noinline
+func div_1_int32(a int32) int32 { return 1 / a }
+
+//go:noinline
+func div_int32_2147483647(a int32) int32 { return a / 2147483647 }
+
+//go:noinline
+func div_2147483647_int32(a int32) int32 { return 2147483647 / a }
+
+//go:noinline
+func mul_int32_Neg2147483648(a int32) int32 { return a * -2147483648 }
+
+//go:noinline
+func mul_Neg2147483648_int32(a int32) int32 { return -2147483648 * a }
+
+//go:noinline
+func mul_int32_Neg2147483647(a int32) int32 { return a * -2147483647 }
+
+//go:noinline
+func mul_Neg2147483647_int32(a int32) int32 { return -2147483647 * a }
+
+//go:noinline
+func mul_int32_Neg1(a int32) int32 { return a * -1 }
+
+//go:noinline
+func mul_Neg1_int32(a int32) int32 { return -1 * a }
+
+//go:noinline
+func mul_int32_0(a int32) int32 { return a * 0 }
+
+//go:noinline
+func mul_0_int32(a int32) int32 { return 0 * a }
+
+//go:noinline
+func mul_int32_1(a int32) int32 { return a * 1 }
+
+//go:noinline
+func mul_1_int32(a int32) int32 { return 1 * a }
+
+//go:noinline
+func mul_int32_2147483647(a int32) int32 { return a * 2147483647 }
+
+//go:noinline
+func mul_2147483647_int32(a int32) int32 { return 2147483647 * a }
+
+//go:noinline
+func mod_int32_Neg2147483648(a int32) int32 { return a % -2147483648 }
+
+//go:noinline
+func mod_Neg2147483648_int32(a int32) int32 { return -2147483648 % a }
+
+//go:noinline
+func mod_int32_Neg2147483647(a int32) int32 { return a % -2147483647 }
+
+//go:noinline
+func mod_Neg2147483647_int32(a int32) int32 { return -2147483647 % a }
+
+//go:noinline
+func mod_int32_Neg1(a int32) int32 { return a % -1 }
+
+//go:noinline
+func mod_Neg1_int32(a int32) int32 { return -1 % a }
+
+//go:noinline
+func mod_0_int32(a int32) int32 { return 0 % a }
+
+//go:noinline
+func mod_int32_1(a int32) int32 { return a % 1 }
+
+//go:noinline
+func mod_1_int32(a int32) int32 { return 1 % a }
+
+//go:noinline
+func mod_int32_2147483647(a int32) int32 { return a % 2147483647 }
+
+//go:noinline
+func mod_2147483647_int32(a int32) int32 { return 2147483647 % a }
+
+//go:noinline
+func and_int32_Neg2147483648(a int32) int32 { return a & -2147483648 }
+
+//go:noinline
+func and_Neg2147483648_int32(a int32) int32 { return -2147483648 & a }
+
+//go:noinline
+func and_int32_Neg2147483647(a int32) int32 { return a & -2147483647 }
+
+//go:noinline
+func and_Neg2147483647_int32(a int32) int32 { return -2147483647 & a }
+
+//go:noinline
+func and_int32_Neg1(a int32) int32 { return a & -1 }
+
+//go:noinline
+func and_Neg1_int32(a int32) int32 { return -1 & a }
+
+//go:noinline
+func and_int32_0(a int32) int32 { return a & 0 }
+
+//go:noinline
+func and_0_int32(a int32) int32 { return 0 & a }
+
+//go:noinline
+func and_int32_1(a int32) int32 { return a & 1 }
+
+//go:noinline
+func and_1_int32(a int32) int32 { return 1 & a }
+
+//go:noinline
+func and_int32_2147483647(a int32) int32 { return a & 2147483647 }
+
+//go:noinline
+func and_2147483647_int32(a int32) int32 { return 2147483647 & a }
+
+//go:noinline
+func or_int32_Neg2147483648(a int32) int32 { return a | -2147483648 }
+
+//go:noinline
+func or_Neg2147483648_int32(a int32) int32 { return -2147483648 | a }
+
+//go:noinline
+func or_int32_Neg2147483647(a int32) int32 { return a | -2147483647 }
+
+//go:noinline
+func or_Neg2147483647_int32(a int32) int32 { return -2147483647 | a }
+
+//go:noinline
+func or_int32_Neg1(a int32) int32 { return a | -1 }
+
+//go:noinline
+func or_Neg1_int32(a int32) int32 { return -1 | a }
+
+//go:noinline
+func or_int32_0(a int32) int32 { return a | 0 }
+
+//go:noinline
+func or_0_int32(a int32) int32 { return 0 | a }
+
+//go:noinline
+func or_int32_1(a int32) int32 { return a | 1 }
+
+//go:noinline
+func or_1_int32(a int32) int32 { return 1 | a }
+
+//go:noinline
+func or_int32_2147483647(a int32) int32 { return a | 2147483647 }
+
+//go:noinline
+func or_2147483647_int32(a int32) int32 { return 2147483647 | a }
+
+//go:noinline
+func xor_int32_Neg2147483648(a int32) int32 { return a ^ -2147483648 }
+
+//go:noinline
+func xor_Neg2147483648_int32(a int32) int32 { return -2147483648 ^ a }
+
+//go:noinline
+func xor_int32_Neg2147483647(a int32) int32 { return a ^ -2147483647 }
+
+//go:noinline
+func xor_Neg2147483647_int32(a int32) int32 { return -2147483647 ^ a }
+
+//go:noinline
+func xor_int32_Neg1(a int32) int32 { return a ^ -1 }
+
+//go:noinline
+func xor_Neg1_int32(a int32) int32 { return -1 ^ a }
+
+//go:noinline
+func xor_int32_0(a int32) int32 { return a ^ 0 }
+
+//go:noinline
+func xor_0_int32(a int32) int32 { return 0 ^ a }
+
+//go:noinline
+func xor_int32_1(a int32) int32 { return a ^ 1 }
+
+//go:noinline
+func xor_1_int32(a int32) int32 { return 1 ^ a }
+
+//go:noinline
+func xor_int32_2147483647(a int32) int32 { return a ^ 2147483647 }
+
+//go:noinline
+func xor_2147483647_int32(a int32) int32 { return 2147483647 ^ a }
+
+//go:noinline
+func mul_int32_Neg9(a int32) int32 { return a * -9 }
+
+//go:noinline
+func mul_Neg9_int32(a int32) int32 { return -9 * a }
+
+//go:noinline
+func mul_int32_Neg5(a int32) int32 { return a * -5 }
+
+//go:noinline
+func mul_Neg5_int32(a int32) int32 { return -5 * a }
+
+//go:noinline
+func mul_int32_Neg3(a int32) int32 { return a * -3 }
+
+//go:noinline
+func mul_Neg3_int32(a int32) int32 { return -3 * a }
+
+//go:noinline
+func mul_int32_3(a int32) int32 { return a * 3 }
+
+//go:noinline
+func mul_3_int32(a int32) int32 { return 3 * a }
+
+//go:noinline
+func mul_int32_5(a int32) int32 { return a * 5 }
+
+//go:noinline
+func mul_5_int32(a int32) int32 { return 5 * a }
+
+//go:noinline
+func mul_int32_7(a int32) int32 { return a * 7 }
+
+//go:noinline
+func mul_7_int32(a int32) int32 { return 7 * a }
+
+//go:noinline
+func mul_int32_9(a int32) int32 { return a * 9 }
+
+//go:noinline
+func mul_9_int32(a int32) int32 { return 9 * a }
+
+//go:noinline
+func mul_int32_10(a int32) int32 { return a * 10 }
+
+//go:noinline
+func mul_10_int32(a int32) int32 { return 10 * a }
+
+//go:noinline
+func mul_int32_11(a int32) int32 { return a * 11 }
+
+//go:noinline
+func mul_11_int32(a int32) int32 { return 11 * a }
+
+//go:noinline
+func mul_int32_13(a int32) int32 { return a * 13 }
+
+//go:noinline
+func mul_13_int32(a int32) int32 { return 13 * a }
+
+//go:noinline
+func mul_int32_19(a int32) int32 { return a * 19 }
+
+//go:noinline
+func mul_19_int32(a int32) int32 { return 19 * a }
+
+//go:noinline
+func mul_int32_21(a int32) int32 { return a * 21 }
+
+//go:noinline
+func mul_21_int32(a int32) int32 { return 21 * a }
+
+//go:noinline
+func mul_int32_25(a int32) int32 { return a * 25 }
+
+//go:noinline
+func mul_25_int32(a int32) int32 { return 25 * a }
+
+//go:noinline
+func mul_int32_27(a int32) int32 { return a * 27 }
+
+//go:noinline
+func mul_27_int32(a int32) int32 { return 27 * a }
+
+//go:noinline
+func mul_int32_37(a int32) int32 { return a * 37 }
+
+//go:noinline
+func mul_37_int32(a int32) int32 { return 37 * a }
+
+//go:noinline
+func mul_int32_41(a int32) int32 { return a * 41 }
+
+//go:noinline
+func mul_41_int32(a int32) int32 { return 41 * a }
+
+//go:noinline
+func mul_int32_45(a int32) int32 { return a * 45 }
+
+//go:noinline
+func mul_45_int32(a int32) int32 { return 45 * a }
+
+//go:noinline
+func mul_int32_73(a int32) int32 { return a * 73 }
+
+//go:noinline
+func mul_73_int32(a int32) int32 { return 73 * a }
+
+//go:noinline
+func mul_int32_81(a int32) int32 { return a * 81 }
+
+//go:noinline
+func mul_81_int32(a int32) int32 { return 81 * a }
+
+//go:noinline
+func add_uint16_0(a uint16) uint16 { return a + 0 }
+
+//go:noinline
+func add_0_uint16(a uint16) uint16 { return 0 + a }
+
+//go:noinline
+func add_uint16_1(a uint16) uint16 { return a + 1 }
+
+//go:noinline
+func add_1_uint16(a uint16) uint16 { return 1 + a }
+
+//go:noinline
+func add_uint16_65535(a uint16) uint16 { return a + 65535 }
+
+//go:noinline
+func add_65535_uint16(a uint16) uint16 { return 65535 + a }
+
+//go:noinline
+func sub_uint16_0(a uint16) uint16 { return a - 0 }
+
+//go:noinline
+func sub_0_uint16(a uint16) uint16 { return 0 - a }
+
+//go:noinline
+func sub_uint16_1(a uint16) uint16 { return a - 1 }
+
+//go:noinline
+func sub_1_uint16(a uint16) uint16 { return 1 - a }
+
+//go:noinline
+func sub_uint16_65535(a uint16) uint16 { return a - 65535 }
+
+//go:noinline
+func sub_65535_uint16(a uint16) uint16 { return 65535 - a }
+
+//go:noinline
+func div_0_uint16(a uint16) uint16 { return 0 / a }
+
+//go:noinline
+func div_uint16_1(a uint16) uint16 { return a / 1 }
+
+//go:noinline
+func div_1_uint16(a uint16) uint16 { return 1 / a }
+
+//go:noinline
+func div_uint16_65535(a uint16) uint16 { return a / 65535 }
+
+//go:noinline
+func div_65535_uint16(a uint16) uint16 { return 65535 / a }
+
+//go:noinline
+func mul_uint16_0(a uint16) uint16 { return a * 0 }
+
+//go:noinline
+func mul_0_uint16(a uint16) uint16 { return 0 * a }
+
+//go:noinline
+func mul_uint16_1(a uint16) uint16 { return a * 1 }
+
+//go:noinline
+func mul_1_uint16(a uint16) uint16 { return 1 * a }
+
+//go:noinline
+func mul_uint16_65535(a uint16) uint16 { return a * 65535 }
+
+//go:noinline
+func mul_65535_uint16(a uint16) uint16 { return 65535 * a }
+
+//go:noinline
+func lsh_uint16_0(a uint16) uint16 { return a << 0 }
+
+//go:noinline
+func lsh_0_uint16(a uint16) uint16 { return 0 << a }
+
+//go:noinline
+func lsh_uint16_1(a uint16) uint16 { return a << 1 }
+
+//go:noinline
+func lsh_1_uint16(a uint16) uint16 { return 1 << a }
+
+//go:noinline
+func lsh_uint16_65535(a uint16) uint16 { return a << 65535 }
+
+//go:noinline
+func lsh_65535_uint16(a uint16) uint16 { return 65535 << a }
+
+//go:noinline
+func rsh_uint16_0(a uint16) uint16 { return a >> 0 }
+
+//go:noinline
+func rsh_0_uint16(a uint16) uint16 { return 0 >> a }
+
+//go:noinline
+func rsh_uint16_1(a uint16) uint16 { return a >> 1 }
+
+//go:noinline
+func rsh_1_uint16(a uint16) uint16 { return 1 >> a }
+
+//go:noinline
+func rsh_uint16_65535(a uint16) uint16 { return a >> 65535 }
+
+//go:noinline
+func rsh_65535_uint16(a uint16) uint16 { return 65535 >> a }
+
+//go:noinline
+func mod_0_uint16(a uint16) uint16 { return 0 % a }
+
+//go:noinline
+func mod_uint16_1(a uint16) uint16 { return a % 1 }
+
+//go:noinline
+func mod_1_uint16(a uint16) uint16 { return 1 % a }
+
+//go:noinline
+func mod_uint16_65535(a uint16) uint16 { return a % 65535 }
+
+//go:noinline
+func mod_65535_uint16(a uint16) uint16 { return 65535 % a }
+
+//go:noinline
+func and_uint16_0(a uint16) uint16 { return a & 0 }
+
+//go:noinline
+func and_0_uint16(a uint16) uint16 { return 0 & a }
+
+//go:noinline
+func and_uint16_1(a uint16) uint16 { return a & 1 }
+
+//go:noinline
+func and_1_uint16(a uint16) uint16 { return 1 & a }
+
+//go:noinline
+func and_uint16_65535(a uint16) uint16 { return a & 65535 }
+
+//go:noinline
+func and_65535_uint16(a uint16) uint16 { return 65535 & a }
+
+//go:noinline
+func or_uint16_0(a uint16) uint16 { return a | 0 }
+
+//go:noinline
+func or_0_uint16(a uint16) uint16 { return 0 | a }
+
+//go:noinline
+func or_uint16_1(a uint16) uint16 { return a | 1 }
+
+//go:noinline
+func or_1_uint16(a uint16) uint16 { return 1 | a }
+
+//go:noinline
+func or_uint16_65535(a uint16) uint16 { return a | 65535 }
+
+//go:noinline
+func or_65535_uint16(a uint16) uint16 { return 65535 | a }
+
+//go:noinline
+func xor_uint16_0(a uint16) uint16 { return a ^ 0 }
+
+//go:noinline
+func xor_0_uint16(a uint16) uint16 { return 0 ^ a }
+
+//go:noinline
+func xor_uint16_1(a uint16) uint16 { return a ^ 1 }
+
+//go:noinline
+func xor_1_uint16(a uint16) uint16 { return 1 ^ a }
+
+//go:noinline
+func xor_uint16_65535(a uint16) uint16 { return a ^ 65535 }
+
+//go:noinline
+func xor_65535_uint16(a uint16) uint16 { return 65535 ^ a }
+
+//go:noinline
+func add_int16_Neg32768(a int16) int16 { return a + -32768 }
+
+//go:noinline
+func add_Neg32768_int16(a int16) int16 { return -32768 + a }
+
+//go:noinline
+func add_int16_Neg32767(a int16) int16 { return a + -32767 }
+
+//go:noinline
+func add_Neg32767_int16(a int16) int16 { return -32767 + a }
+
+//go:noinline
+func add_int16_Neg1(a int16) int16 { return a + -1 }
+
+//go:noinline
+func add_Neg1_int16(a int16) int16 { return -1 + a }
+
+//go:noinline
+func add_int16_0(a int16) int16 { return a + 0 }
+
+//go:noinline
+func add_0_int16(a int16) int16 { return 0 + a }
+
+//go:noinline
+func add_int16_1(a int16) int16 { return a + 1 }
+
+//go:noinline
+func add_1_int16(a int16) int16 { return 1 + a }
+
+//go:noinline
+func add_int16_32766(a int16) int16 { return a + 32766 }
+
+//go:noinline
+func add_32766_int16(a int16) int16 { return 32766 + a }
+
+//go:noinline
+func add_int16_32767(a int16) int16 { return a + 32767 }
+
+//go:noinline
+func add_32767_int16(a int16) int16 { return 32767 + a }
+
+//go:noinline
+func sub_int16_Neg32768(a int16) int16 { return a - -32768 }
+
+//go:noinline
+func sub_Neg32768_int16(a int16) int16 { return -32768 - a }
+
+//go:noinline
+func sub_int16_Neg32767(a int16) int16 { return a - -32767 }
+
+//go:noinline
+func sub_Neg32767_int16(a int16) int16 { return -32767 - a }
+
+//go:noinline
+func sub_int16_Neg1(a int16) int16 { return a - -1 }
+
+//go:noinline
+func sub_Neg1_int16(a int16) int16 { return -1 - a }
+
+//go:noinline
+func sub_int16_0(a int16) int16 { return a - 0 }
+
+//go:noinline
+func sub_0_int16(a int16) int16 { return 0 - a }
+
+//go:noinline
+func sub_int16_1(a int16) int16 { return a - 1 }
+
+//go:noinline
+func sub_1_int16(a int16) int16 { return 1 - a }
+
+//go:noinline
+func sub_int16_32766(a int16) int16 { return a - 32766 }
+
+//go:noinline
+func sub_32766_int16(a int16) int16 { return 32766 - a }
+
+//go:noinline
+func sub_int16_32767(a int16) int16 { return a - 32767 }
+
+//go:noinline
+func sub_32767_int16(a int16) int16 { return 32767 - a }
+
+//go:noinline
+func div_int16_Neg32768(a int16) int16 { return a / -32768 }
+
+//go:noinline
+func div_Neg32768_int16(a int16) int16 { return -32768 / a }
+
+//go:noinline
+func div_int16_Neg32767(a int16) int16 { return a / -32767 }
+
+//go:noinline
+func div_Neg32767_int16(a int16) int16 { return -32767 / a }
+
+//go:noinline
+func div_int16_Neg1(a int16) int16 { return a / -1 }
+
+//go:noinline
+func div_Neg1_int16(a int16) int16 { return -1 / a }
+
+//go:noinline
+func div_0_int16(a int16) int16 { return 0 / a }
+
+//go:noinline
+func div_int16_1(a int16) int16 { return a / 1 }
+
+//go:noinline
+func div_1_int16(a int16) int16 { return 1 / a }
+
+//go:noinline
+func div_int16_32766(a int16) int16 { return a / 32766 }
+
+//go:noinline
+func div_32766_int16(a int16) int16 { return 32766 / a }
+
+//go:noinline
+func div_int16_32767(a int16) int16 { return a / 32767 }
+
+//go:noinline
+func div_32767_int16(a int16) int16 { return 32767 / a }
+
+//go:noinline
+func mul_int16_Neg32768(a int16) int16 { return a * -32768 }
+
+//go:noinline
+func mul_Neg32768_int16(a int16) int16 { return -32768 * a }
+
+//go:noinline
+func mul_int16_Neg32767(a int16) int16 { return a * -32767 }
+
+//go:noinline
+func mul_Neg32767_int16(a int16) int16 { return -32767 * a }
+
+//go:noinline
+func mul_int16_Neg1(a int16) int16 { return a * -1 }
+
+//go:noinline
+func mul_Neg1_int16(a int16) int16 { return -1 * a }
+
+//go:noinline
+func mul_int16_0(a int16) int16 { return a * 0 }
+
+//go:noinline
+func mul_0_int16(a int16) int16 { return 0 * a }
+
+//go:noinline
+func mul_int16_1(a int16) int16 { return a * 1 }
+
+//go:noinline
+func mul_1_int16(a int16) int16 { return 1 * a }
+
+//go:noinline
+func mul_int16_32766(a int16) int16 { return a * 32766 }
+
+//go:noinline
+func mul_32766_int16(a int16) int16 { return 32766 * a }
+
+//go:noinline
+func mul_int16_32767(a int16) int16 { return a * 32767 }
+
+//go:noinline
+func mul_32767_int16(a int16) int16 { return 32767 * a }
+
+//go:noinline
+func mod_int16_Neg32768(a int16) int16 { return a % -32768 }
+
+//go:noinline
+func mod_Neg32768_int16(a int16) int16 { return -32768 % a }
+
+//go:noinline
+func mod_int16_Neg32767(a int16) int16 { return a % -32767 }
+
+//go:noinline
+func mod_Neg32767_int16(a int16) int16 { return -32767 % a }
+
+//go:noinline
+func mod_int16_Neg1(a int16) int16 { return a % -1 }
+
+//go:noinline
+func mod_Neg1_int16(a int16) int16 { return -1 % a }
+
+//go:noinline
+func mod_0_int16(a int16) int16 { return 0 % a }
+
+//go:noinline
+func mod_int16_1(a int16) int16 { return a % 1 }
+
+//go:noinline
+func mod_1_int16(a int16) int16 { return 1 % a }
+
+//go:noinline
+func mod_int16_32766(a int16) int16 { return a % 32766 }
+
+//go:noinline
+func mod_32766_int16(a int16) int16 { return 32766 % a }
+
+//go:noinline
+func mod_int16_32767(a int16) int16 { return a % 32767 }
+
+//go:noinline
+func mod_32767_int16(a int16) int16 { return 32767 % a }
+
+//go:noinline
+func and_int16_Neg32768(a int16) int16 { return a & -32768 }
+
+//go:noinline
+func and_Neg32768_int16(a int16) int16 { return -32768 & a }
+
+//go:noinline
+func and_int16_Neg32767(a int16) int16 { return a & -32767 }
+
+//go:noinline
+func and_Neg32767_int16(a int16) int16 { return -32767 & a }
+
+//go:noinline
+func and_int16_Neg1(a int16) int16 { return a & -1 }
+
+//go:noinline
+func and_Neg1_int16(a int16) int16 { return -1 & a }
+
+//go:noinline
+func and_int16_0(a int16) int16 { return a & 0 }
+
+//go:noinline
+func and_0_int16(a int16) int16 { return 0 & a }
+
+//go:noinline
+func and_int16_1(a int16) int16 { return a & 1 }
+
+//go:noinline
+func and_1_int16(a int16) int16 { return 1 & a }
+
+//go:noinline
+func and_int16_32766(a int16) int16 { return a & 32766 }
+
+//go:noinline
+func and_32766_int16(a int16) int16 { return 32766 & a }
+
+//go:noinline
+func and_int16_32767(a int16) int16 { return a & 32767 }
+
+//go:noinline
+func and_32767_int16(a int16) int16 { return 32767 & a }
+
+//go:noinline
+func or_int16_Neg32768(a int16) int16 { return a | -32768 }
+
+//go:noinline
+func or_Neg32768_int16(a int16) int16 { return -32768 | a }
+
+//go:noinline
+func or_int16_Neg32767(a int16) int16 { return a | -32767 }
+
+//go:noinline
+func or_Neg32767_int16(a int16) int16 { return -32767 | a }
+
+//go:noinline
+func or_int16_Neg1(a int16) int16 { return a | -1 }
+
+//go:noinline
+func or_Neg1_int16(a int16) int16 { return -1 | a }
+
+//go:noinline
+func or_int16_0(a int16) int16 { return a | 0 }
+
+//go:noinline
+func or_0_int16(a int16) int16 { return 0 | a }
+
+//go:noinline
+func or_int16_1(a int16) int16 { return a | 1 }
+
+//go:noinline
+func or_1_int16(a int16) int16 { return 1 | a }
+
+//go:noinline
+func or_int16_32766(a int16) int16 { return a | 32766 }
+
+//go:noinline
+func or_32766_int16(a int16) int16 { return 32766 | a }
+
+//go:noinline
+func or_int16_32767(a int16) int16 { return a | 32767 }
+
+//go:noinline
+func or_32767_int16(a int16) int16 { return 32767 | a }
+
+//go:noinline
+func xor_int16_Neg32768(a int16) int16 { return a ^ -32768 }
+
+//go:noinline
+func xor_Neg32768_int16(a int16) int16 { return -32768 ^ a }
+
+//go:noinline
+func xor_int16_Neg32767(a int16) int16 { return a ^ -32767 }
+
+//go:noinline
+func xor_Neg32767_int16(a int16) int16 { return -32767 ^ a }
+
+//go:noinline
+func xor_int16_Neg1(a int16) int16 { return a ^ -1 }
+
+//go:noinline
+func xor_Neg1_int16(a int16) int16 { return -1 ^ a }
+
+//go:noinline
+func xor_int16_0(a int16) int16 { return a ^ 0 }
+
+//go:noinline
+func xor_0_int16(a int16) int16 { return 0 ^ a }
+
+//go:noinline
+func xor_int16_1(a int16) int16 { return a ^ 1 }
+
+//go:noinline
+func xor_1_int16(a int16) int16 { return 1 ^ a }
+
+//go:noinline
+func xor_int16_32766(a int16) int16 { return a ^ 32766 }
+
+//go:noinline
+func xor_32766_int16(a int16) int16 { return 32766 ^ a }
+
+//go:noinline
+func xor_int16_32767(a int16) int16 { return a ^ 32767 }
+
+//go:noinline
+func xor_32767_int16(a int16) int16 { return 32767 ^ a }
+
+//go:noinline
+func add_uint8_0(a uint8) uint8 { return a + 0 }
+
+//go:noinline
+func add_0_uint8(a uint8) uint8 { return 0 + a }
+
+//go:noinline
+func add_uint8_1(a uint8) uint8 { return a + 1 }
+
+//go:noinline
+func add_1_uint8(a uint8) uint8 { return 1 + a }
+
+//go:noinline
+func add_uint8_255(a uint8) uint8 { return a + 255 }
+
+//go:noinline
+func add_255_uint8(a uint8) uint8 { return 255 + a }
+
+//go:noinline
+func sub_uint8_0(a uint8) uint8 { return a - 0 }
+
+//go:noinline
+func sub_0_uint8(a uint8) uint8 { return 0 - a }
+
+//go:noinline
+func sub_uint8_1(a uint8) uint8 { return a - 1 }
+
+//go:noinline
+func sub_1_uint8(a uint8) uint8 { return 1 - a }
+
+//go:noinline
+func sub_uint8_255(a uint8) uint8 { return a - 255 }
+
+//go:noinline
+func sub_255_uint8(a uint8) uint8 { return 255 - a }
+
+//go:noinline
+func div_0_uint8(a uint8) uint8 { return 0 / a }
+
+//go:noinline
+func div_uint8_1(a uint8) uint8 { return a / 1 }
+
+//go:noinline
+func div_1_uint8(a uint8) uint8 { return 1 / a }
+
+//go:noinline
+func div_uint8_255(a uint8) uint8 { return a / 255 }
+
+//go:noinline
+func div_255_uint8(a uint8) uint8 { return 255 / a }
+
+//go:noinline
+func mul_uint8_0(a uint8) uint8 { return a * 0 }
+
+//go:noinline
+func mul_0_uint8(a uint8) uint8 { return 0 * a }
+
+//go:noinline
+func mul_uint8_1(a uint8) uint8 { return a * 1 }
+
+//go:noinline
+func mul_1_uint8(a uint8) uint8 { return 1 * a }
+
+//go:noinline
+func mul_uint8_255(a uint8) uint8 { return a * 255 }
+
+//go:noinline
+func mul_255_uint8(a uint8) uint8 { return 255 * a }
+
+//go:noinline
+func lsh_uint8_0(a uint8) uint8 { return a << 0 }
+
+//go:noinline
+func lsh_0_uint8(a uint8) uint8 { return 0 << a }
+
+//go:noinline
+func lsh_uint8_1(a uint8) uint8 { return a << 1 }
+
+//go:noinline
+func lsh_1_uint8(a uint8) uint8 { return 1 << a }
+
+//go:noinline
+func lsh_uint8_255(a uint8) uint8 { return a << 255 }
+
+//go:noinline
+func lsh_255_uint8(a uint8) uint8 { return 255 << a }
+
+//go:noinline
+func rsh_uint8_0(a uint8) uint8 { return a >> 0 }
+
+//go:noinline
+func rsh_0_uint8(a uint8) uint8 { return 0 >> a }
+
+//go:noinline
+func rsh_uint8_1(a uint8) uint8 { return a >> 1 }
+
+//go:noinline
+func rsh_1_uint8(a uint8) uint8 { return 1 >> a }
+
+//go:noinline
+func rsh_uint8_255(a uint8) uint8 { return a >> 255 }
+
+//go:noinline
+func rsh_255_uint8(a uint8) uint8 { return 255 >> a }
+
+//go:noinline
+func mod_0_uint8(a uint8) uint8 { return 0 % a }
+
+//go:noinline
+func mod_uint8_1(a uint8) uint8 { return a % 1 }
+
+//go:noinline
+func mod_1_uint8(a uint8) uint8 { return 1 % a }
+
+//go:noinline
+func mod_uint8_255(a uint8) uint8 { return a % 255 }
+
+//go:noinline
+func mod_255_uint8(a uint8) uint8 { return 255 % a }
+
+//go:noinline
+func and_uint8_0(a uint8) uint8 { return a & 0 }
+
+//go:noinline
+func and_0_uint8(a uint8) uint8 { return 0 & a }
+
+//go:noinline
+func and_uint8_1(a uint8) uint8 { return a & 1 }
+
+//go:noinline
+func and_1_uint8(a uint8) uint8 { return 1 & a }
+
+//go:noinline
+func and_uint8_255(a uint8) uint8 { return a & 255 }
+
+//go:noinline
+func and_255_uint8(a uint8) uint8 { return 255 & a }
+
+//go:noinline
+func or_uint8_0(a uint8) uint8 { return a | 0 }
+
+//go:noinline
+func or_0_uint8(a uint8) uint8 { return 0 | a }
+
+//go:noinline
+func or_uint8_1(a uint8) uint8 { return a | 1 }
+
+//go:noinline
+func or_1_uint8(a uint8) uint8 { return 1 | a }
+
+//go:noinline
+func or_uint8_255(a uint8) uint8 { return a | 255 }
+
+//go:noinline
+func or_255_uint8(a uint8) uint8 { return 255 | a }
+
+//go:noinline
+func xor_uint8_0(a uint8) uint8 { return a ^ 0 }
+
+//go:noinline
+func xor_0_uint8(a uint8) uint8 { return 0 ^ a }
+
+//go:noinline
+func xor_uint8_1(a uint8) uint8 { return a ^ 1 }
+
+//go:noinline
+func xor_1_uint8(a uint8) uint8 { return 1 ^ a }
+
+//go:noinline
+func xor_uint8_255(a uint8) uint8 { return a ^ 255 }
+
+//go:noinline
+func xor_255_uint8(a uint8) uint8 { return 255 ^ a }
+
+//go:noinline
+func add_int8_Neg128(a int8) int8 { return a + -128 }
+
+//go:noinline
+func add_Neg128_int8(a int8) int8 { return -128 + a }
+
+//go:noinline
+func add_int8_Neg127(a int8) int8 { return a + -127 }
+
+//go:noinline
+func add_Neg127_int8(a int8) int8 { return -127 + a }
+
+//go:noinline
+func add_int8_Neg1(a int8) int8 { return a + -1 }
+
+//go:noinline
+func add_Neg1_int8(a int8) int8 { return -1 + a }
+
+//go:noinline
+func add_int8_0(a int8) int8 { return a + 0 }
+
+//go:noinline
+func add_0_int8(a int8) int8 { return 0 + a }
+
+//go:noinline
+func add_int8_1(a int8) int8 { return a + 1 }
+
+//go:noinline
+func add_1_int8(a int8) int8 { return 1 + a }
+
+//go:noinline
+func add_int8_126(a int8) int8 { return a + 126 }
+
+//go:noinline
+func add_126_int8(a int8) int8 { return 126 + a }
+
+//go:noinline
+func add_int8_127(a int8) int8 { return a + 127 }
+
+//go:noinline
+func add_127_int8(a int8) int8 { return 127 + a }
+
+//go:noinline
+func sub_int8_Neg128(a int8) int8 { return a - -128 }
+
+//go:noinline
+func sub_Neg128_int8(a int8) int8 { return -128 - a }
+
+//go:noinline
+func sub_int8_Neg127(a int8) int8 { return a - -127 }
+
+//go:noinline
+func sub_Neg127_int8(a int8) int8 { return -127 - a }
+
+//go:noinline
+func sub_int8_Neg1(a int8) int8 { return a - -1 }
+
+//go:noinline
+func sub_Neg1_int8(a int8) int8 { return -1 - a }
+
+//go:noinline
+func sub_int8_0(a int8) int8 { return a - 0 }
+
+//go:noinline
+func sub_0_int8(a int8) int8 { return 0 - a }
+
+//go:noinline
+func sub_int8_1(a int8) int8 { return a - 1 }
+
+//go:noinline
+func sub_1_int8(a int8) int8 { return 1 - a }
+
+//go:noinline
+func sub_int8_126(a int8) int8 { return a - 126 }
+
+//go:noinline
+func sub_126_int8(a int8) int8 { return 126 - a }
+
+//go:noinline
+func sub_int8_127(a int8) int8 { return a - 127 }
+
+//go:noinline
+func sub_127_int8(a int8) int8 { return 127 - a }
+
+//go:noinline
+func div_int8_Neg128(a int8) int8 { return a / -128 }
+
+//go:noinline
+func div_Neg128_int8(a int8) int8 { return -128 / a }
+
+//go:noinline
+func div_int8_Neg127(a int8) int8 { return a / -127 }
+
+//go:noinline
+func div_Neg127_int8(a int8) int8 { return -127 / a }
+
+//go:noinline
+func div_int8_Neg1(a int8) int8 { return a / -1 }
+
+//go:noinline
+func div_Neg1_int8(a int8) int8 { return -1 / a }
+
+//go:noinline
+func div_0_int8(a int8) int8 { return 0 / a }
+
+//go:noinline
+func div_int8_1(a int8) int8 { return a / 1 }
+
+//go:noinline
+func div_1_int8(a int8) int8 { return 1 / a }
+
+//go:noinline
+func div_int8_126(a int8) int8 { return a / 126 }
+
+//go:noinline
+func div_126_int8(a int8) int8 { return 126 / a }
+
+//go:noinline
+func div_int8_127(a int8) int8 { return a / 127 }
+
+//go:noinline
+func div_127_int8(a int8) int8 { return 127 / a }
+
+//go:noinline
+func mul_int8_Neg128(a int8) int8 { return a * -128 }
+
+//go:noinline
+func mul_Neg128_int8(a int8) int8 { return -128 * a }
+
+//go:noinline
+func mul_int8_Neg127(a int8) int8 { return a * -127 }
+
+//go:noinline
+func mul_Neg127_int8(a int8) int8 { return -127 * a }
+
+//go:noinline
+func mul_int8_Neg1(a int8) int8 { return a * -1 }
+
+//go:noinline
+func mul_Neg1_int8(a int8) int8 { return -1 * a }
+
+//go:noinline
+func mul_int8_0(a int8) int8 { return a * 0 }
+
+//go:noinline
+func mul_0_int8(a int8) int8 { return 0 * a }
+
+//go:noinline
+func mul_int8_1(a int8) int8 { return a * 1 }
+
+//go:noinline
+func mul_1_int8(a int8) int8 { return 1 * a }
+
+//go:noinline
+func mul_int8_126(a int8) int8 { return a * 126 }
+
+//go:noinline
+func mul_126_int8(a int8) int8 { return 126 * a }
+
+//go:noinline
+func mul_int8_127(a int8) int8 { return a * 127 }
+
+//go:noinline
+func mul_127_int8(a int8) int8 { return 127 * a }
+
+//go:noinline
+func mod_int8_Neg128(a int8) int8 { return a % -128 }
+
+//go:noinline
+func mod_Neg128_int8(a int8) int8 { return -128 % a }
+
+//go:noinline
+func mod_int8_Neg127(a int8) int8 { return a % -127 }
+
+//go:noinline
+func mod_Neg127_int8(a int8) int8 { return -127 % a }
+
+//go:noinline
+func mod_int8_Neg1(a int8) int8 { return a % -1 }
+
+//go:noinline
+func mod_Neg1_int8(a int8) int8 { return -1 % a }
+
+//go:noinline
+func mod_0_int8(a int8) int8 { return 0 % a }
+
+//go:noinline
+func mod_int8_1(a int8) int8 { return a % 1 }
+
+//go:noinline
+func mod_1_int8(a int8) int8 { return 1 % a }
+
+//go:noinline
+func mod_int8_126(a int8) int8 { return a % 126 }
+
+//go:noinline
+func mod_126_int8(a int8) int8 { return 126 % a }
+
+//go:noinline
+func mod_int8_127(a int8) int8 { return a % 127 }
+
+//go:noinline
+func mod_127_int8(a int8) int8 { return 127 % a }
+
+//go:noinline
+func and_int8_Neg128(a int8) int8 { return a & -128 }
+
+//go:noinline
+func and_Neg128_int8(a int8) int8 { return -128 & a }
+
+//go:noinline
+func and_int8_Neg127(a int8) int8 { return a & -127 }
+
+//go:noinline
+func and_Neg127_int8(a int8) int8 { return -127 & a }
+
+//go:noinline
+func and_int8_Neg1(a int8) int8 { return a & -1 }
+
+//go:noinline
+func and_Neg1_int8(a int8) int8 { return -1 & a }
+
+//go:noinline
+func and_int8_0(a int8) int8 { return a & 0 }
+
+//go:noinline
+func and_0_int8(a int8) int8 { return 0 & a }
+
+//go:noinline
+func and_int8_1(a int8) int8 { return a & 1 }
+
+//go:noinline
+func and_1_int8(a int8) int8 { return 1 & a }
+
+//go:noinline
+func and_int8_126(a int8) int8 { return a & 126 }
+
+//go:noinline
+func and_126_int8(a int8) int8 { return 126 & a }
+
+//go:noinline
+func and_int8_127(a int8) int8 { return a & 127 }
+
+//go:noinline
+func and_127_int8(a int8) int8 { return 127 & a }
+
+//go:noinline
+func or_int8_Neg128(a int8) int8 { return a | -128 }
+
+//go:noinline
+func or_Neg128_int8(a int8) int8 { return -128 | a }
+
+//go:noinline
+func or_int8_Neg127(a int8) int8 { return a | -127 }
+
+//go:noinline
+func or_Neg127_int8(a int8) int8 { return -127 | a }
+
+//go:noinline
+func or_int8_Neg1(a int8) int8 { return a | -1 }
+
+//go:noinline
+func or_Neg1_int8(a int8) int8 { return -1 | a }
+
+//go:noinline
+func or_int8_0(a int8) int8 { return a | 0 }
+
+//go:noinline
+func or_0_int8(a int8) int8 { return 0 | a }
+
+//go:noinline
+func or_int8_1(a int8) int8 { return a | 1 }
+
+//go:noinline
+func or_1_int8(a int8) int8 { return 1 | a }
+
+//go:noinline
+func or_int8_126(a int8) int8 { return a | 126 }
+
+//go:noinline
+func or_126_int8(a int8) int8 { return 126 | a }
+
+//go:noinline
+func or_int8_127(a int8) int8 { return a | 127 }
+
+//go:noinline
+func or_127_int8(a int8) int8 { return 127 | a }
+
+//go:noinline
+func xor_int8_Neg128(a int8) int8 { return a ^ -128 }
+
+//go:noinline
+func xor_Neg128_int8(a int8) int8 { return -128 ^ a }
+
+//go:noinline
+func xor_int8_Neg127(a int8) int8 { return a ^ -127 }
+
+//go:noinline
+func xor_Neg127_int8(a int8) int8 { return -127 ^ a }
+
+//go:noinline
+func xor_int8_Neg1(a int8) int8 { return a ^ -1 }
+
+//go:noinline
+func xor_Neg1_int8(a int8) int8 { return -1 ^ a }
+
+//go:noinline
+func xor_int8_0(a int8) int8 { return a ^ 0 }
+
+//go:noinline
+func xor_0_int8(a int8) int8 { return 0 ^ a }
+
+//go:noinline
+func xor_int8_1(a int8) int8 { return a ^ 1 }
+
+//go:noinline
+func xor_1_int8(a int8) int8 { return 1 ^ a }
+
+//go:noinline
+func xor_int8_126(a int8) int8 { return a ^ 126 }
+
+//go:noinline
+func xor_126_int8(a int8) int8 { return 126 ^ a }
+
+//go:noinline
+func xor_int8_127(a int8) int8 { return a ^ 127 }
+
+//go:noinline
+func xor_127_int8(a int8) int8 { return 127 ^ a }
+
+type test_uint64 struct {
+ fn func(uint64) uint64
+ fnname string
+ in uint64
+ want uint64
+}
+
+var tests_uint64 = []test_uint64{
+
+ test_uint64{fn: add_0_uint64, fnname: "add_0_uint64", in: 0, want: 0},
+ test_uint64{fn: add_uint64_0, fnname: "add_uint64_0", in: 0, want: 0},
+ test_uint64{fn: add_0_uint64, fnname: "add_0_uint64", in: 1, want: 1},
+ test_uint64{fn: add_uint64_0, fnname: "add_uint64_0", in: 1, want: 1},
+ test_uint64{fn: add_0_uint64, fnname: "add_0_uint64", in: 4294967296, want: 4294967296},
+ test_uint64{fn: add_uint64_0, fnname: "add_uint64_0", in: 4294967296, want: 4294967296},
+ test_uint64{fn: add_0_uint64, fnname: "add_0_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: add_uint64_0, fnname: "add_uint64_0", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: add_0_uint64, fnname: "add_0_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: add_uint64_0, fnname: "add_uint64_0", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: add_1_uint64, fnname: "add_1_uint64", in: 0, want: 1},
+ test_uint64{fn: add_uint64_1, fnname: "add_uint64_1", in: 0, want: 1},
+ test_uint64{fn: add_1_uint64, fnname: "add_1_uint64", in: 1, want: 2},
+ test_uint64{fn: add_uint64_1, fnname: "add_uint64_1", in: 1, want: 2},
+ test_uint64{fn: add_1_uint64, fnname: "add_1_uint64", in: 4294967296, want: 4294967297},
+ test_uint64{fn: add_uint64_1, fnname: "add_uint64_1", in: 4294967296, want: 4294967297},
+ test_uint64{fn: add_1_uint64, fnname: "add_1_uint64", in: 9223372036854775808, want: 9223372036854775809},
+ test_uint64{fn: add_uint64_1, fnname: "add_uint64_1", in: 9223372036854775808, want: 9223372036854775809},
+ test_uint64{fn: add_1_uint64, fnname: "add_1_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: add_uint64_1, fnname: "add_uint64_1", in: 18446744073709551615, want: 0},
+ test_uint64{fn: add_4294967296_uint64, fnname: "add_4294967296_uint64", in: 0, want: 4294967296},
+ test_uint64{fn: add_uint64_4294967296, fnname: "add_uint64_4294967296", in: 0, want: 4294967296},
+ test_uint64{fn: add_4294967296_uint64, fnname: "add_4294967296_uint64", in: 1, want: 4294967297},
+ test_uint64{fn: add_uint64_4294967296, fnname: "add_uint64_4294967296", in: 1, want: 4294967297},
+ test_uint64{fn: add_4294967296_uint64, fnname: "add_4294967296_uint64", in: 4294967296, want: 8589934592},
+ test_uint64{fn: add_uint64_4294967296, fnname: "add_uint64_4294967296", in: 4294967296, want: 8589934592},
+ test_uint64{fn: add_4294967296_uint64, fnname: "add_4294967296_uint64", in: 9223372036854775808, want: 9223372041149743104},
+ test_uint64{fn: add_uint64_4294967296, fnname: "add_uint64_4294967296", in: 9223372036854775808, want: 9223372041149743104},
+ test_uint64{fn: add_4294967296_uint64, fnname: "add_4294967296_uint64", in: 18446744073709551615, want: 4294967295},
+ test_uint64{fn: add_uint64_4294967296, fnname: "add_uint64_4294967296", in: 18446744073709551615, want: 4294967295},
+ test_uint64{fn: add_9223372036854775808_uint64, fnname: "add_9223372036854775808_uint64", in: 0, want: 9223372036854775808},
+ test_uint64{fn: add_uint64_9223372036854775808, fnname: "add_uint64_9223372036854775808", in: 0, want: 9223372036854775808},
+ test_uint64{fn: add_9223372036854775808_uint64, fnname: "add_9223372036854775808_uint64", in: 1, want: 9223372036854775809},
+ test_uint64{fn: add_uint64_9223372036854775808, fnname: "add_uint64_9223372036854775808", in: 1, want: 9223372036854775809},
+ test_uint64{fn: add_9223372036854775808_uint64, fnname: "add_9223372036854775808_uint64", in: 4294967296, want: 9223372041149743104},
+ test_uint64{fn: add_uint64_9223372036854775808, fnname: "add_uint64_9223372036854775808", in: 4294967296, want: 9223372041149743104},
+ test_uint64{fn: add_9223372036854775808_uint64, fnname: "add_9223372036854775808_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: add_uint64_9223372036854775808, fnname: "add_uint64_9223372036854775808", in: 9223372036854775808, want: 0},
+ test_uint64{fn: add_9223372036854775808_uint64, fnname: "add_9223372036854775808_uint64", in: 18446744073709551615, want: 9223372036854775807},
+ test_uint64{fn: add_uint64_9223372036854775808, fnname: "add_uint64_9223372036854775808", in: 18446744073709551615, want: 9223372036854775807},
+ test_uint64{fn: add_18446744073709551615_uint64, fnname: "add_18446744073709551615_uint64", in: 0, want: 18446744073709551615},
+ test_uint64{fn: add_uint64_18446744073709551615, fnname: "add_uint64_18446744073709551615", in: 0, want: 18446744073709551615},
+ test_uint64{fn: add_18446744073709551615_uint64, fnname: "add_18446744073709551615_uint64", in: 1, want: 0},
+ test_uint64{fn: add_uint64_18446744073709551615, fnname: "add_uint64_18446744073709551615", in: 1, want: 0},
+ test_uint64{fn: add_18446744073709551615_uint64, fnname: "add_18446744073709551615_uint64", in: 4294967296, want: 4294967295},
+ test_uint64{fn: add_uint64_18446744073709551615, fnname: "add_uint64_18446744073709551615", in: 4294967296, want: 4294967295},
+ test_uint64{fn: add_18446744073709551615_uint64, fnname: "add_18446744073709551615_uint64", in: 9223372036854775808, want: 9223372036854775807},
+ test_uint64{fn: add_uint64_18446744073709551615, fnname: "add_uint64_18446744073709551615", in: 9223372036854775808, want: 9223372036854775807},
+ test_uint64{fn: add_18446744073709551615_uint64, fnname: "add_18446744073709551615_uint64", in: 18446744073709551615, want: 18446744073709551614},
+ test_uint64{fn: add_uint64_18446744073709551615, fnname: "add_uint64_18446744073709551615", in: 18446744073709551615, want: 18446744073709551614},
+ test_uint64{fn: sub_0_uint64, fnname: "sub_0_uint64", in: 0, want: 0},
+ test_uint64{fn: sub_uint64_0, fnname: "sub_uint64_0", in: 0, want: 0},
+ test_uint64{fn: sub_0_uint64, fnname: "sub_0_uint64", in: 1, want: 18446744073709551615},
+ test_uint64{fn: sub_uint64_0, fnname: "sub_uint64_0", in: 1, want: 1},
+ test_uint64{fn: sub_0_uint64, fnname: "sub_0_uint64", in: 4294967296, want: 18446744069414584320},
+ test_uint64{fn: sub_uint64_0, fnname: "sub_uint64_0", in: 4294967296, want: 4294967296},
+ test_uint64{fn: sub_0_uint64, fnname: "sub_0_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: sub_uint64_0, fnname: "sub_uint64_0", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: sub_0_uint64, fnname: "sub_0_uint64", in: 18446744073709551615, want: 1},
+ test_uint64{fn: sub_uint64_0, fnname: "sub_uint64_0", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: sub_1_uint64, fnname: "sub_1_uint64", in: 0, want: 1},
+ test_uint64{fn: sub_uint64_1, fnname: "sub_uint64_1", in: 0, want: 18446744073709551615},
+ test_uint64{fn: sub_1_uint64, fnname: "sub_1_uint64", in: 1, want: 0},
+ test_uint64{fn: sub_uint64_1, fnname: "sub_uint64_1", in: 1, want: 0},
+ test_uint64{fn: sub_1_uint64, fnname: "sub_1_uint64", in: 4294967296, want: 18446744069414584321},
+ test_uint64{fn: sub_uint64_1, fnname: "sub_uint64_1", in: 4294967296, want: 4294967295},
+ test_uint64{fn: sub_1_uint64, fnname: "sub_1_uint64", in: 9223372036854775808, want: 9223372036854775809},
+ test_uint64{fn: sub_uint64_1, fnname: "sub_uint64_1", in: 9223372036854775808, want: 9223372036854775807},
+ test_uint64{fn: sub_1_uint64, fnname: "sub_1_uint64", in: 18446744073709551615, want: 2},
+ test_uint64{fn: sub_uint64_1, fnname: "sub_uint64_1", in: 18446744073709551615, want: 18446744073709551614},
+ test_uint64{fn: sub_4294967296_uint64, fnname: "sub_4294967296_uint64", in: 0, want: 4294967296},
+ test_uint64{fn: sub_uint64_4294967296, fnname: "sub_uint64_4294967296", in: 0, want: 18446744069414584320},
+ test_uint64{fn: sub_4294967296_uint64, fnname: "sub_4294967296_uint64", in: 1, want: 4294967295},
+ test_uint64{fn: sub_uint64_4294967296, fnname: "sub_uint64_4294967296", in: 1, want: 18446744069414584321},
+ test_uint64{fn: sub_4294967296_uint64, fnname: "sub_4294967296_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: sub_uint64_4294967296, fnname: "sub_uint64_4294967296", in: 4294967296, want: 0},
+ test_uint64{fn: sub_4294967296_uint64, fnname: "sub_4294967296_uint64", in: 9223372036854775808, want: 9223372041149743104},
+ test_uint64{fn: sub_uint64_4294967296, fnname: "sub_uint64_4294967296", in: 9223372036854775808, want: 9223372032559808512},
+ test_uint64{fn: sub_4294967296_uint64, fnname: "sub_4294967296_uint64", in: 18446744073709551615, want: 4294967297},
+ test_uint64{fn: sub_uint64_4294967296, fnname: "sub_uint64_4294967296", in: 18446744073709551615, want: 18446744069414584319},
+ test_uint64{fn: sub_9223372036854775808_uint64, fnname: "sub_9223372036854775808_uint64", in: 0, want: 9223372036854775808},
+ test_uint64{fn: sub_uint64_9223372036854775808, fnname: "sub_uint64_9223372036854775808", in: 0, want: 9223372036854775808},
+ test_uint64{fn: sub_9223372036854775808_uint64, fnname: "sub_9223372036854775808_uint64", in: 1, want: 9223372036854775807},
+ test_uint64{fn: sub_uint64_9223372036854775808, fnname: "sub_uint64_9223372036854775808", in: 1, want: 9223372036854775809},
+ test_uint64{fn: sub_9223372036854775808_uint64, fnname: "sub_9223372036854775808_uint64", in: 4294967296, want: 9223372032559808512},
+ test_uint64{fn: sub_uint64_9223372036854775808, fnname: "sub_uint64_9223372036854775808", in: 4294967296, want: 9223372041149743104},
+ test_uint64{fn: sub_9223372036854775808_uint64, fnname: "sub_9223372036854775808_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: sub_uint64_9223372036854775808, fnname: "sub_uint64_9223372036854775808", in: 9223372036854775808, want: 0},
+ test_uint64{fn: sub_9223372036854775808_uint64, fnname: "sub_9223372036854775808_uint64", in: 18446744073709551615, want: 9223372036854775809},
+ test_uint64{fn: sub_uint64_9223372036854775808, fnname: "sub_uint64_9223372036854775808", in: 18446744073709551615, want: 9223372036854775807},
+ test_uint64{fn: sub_18446744073709551615_uint64, fnname: "sub_18446744073709551615_uint64", in: 0, want: 18446744073709551615},
+ test_uint64{fn: sub_uint64_18446744073709551615, fnname: "sub_uint64_18446744073709551615", in: 0, want: 1},
+ test_uint64{fn: sub_18446744073709551615_uint64, fnname: "sub_18446744073709551615_uint64", in: 1, want: 18446744073709551614},
+ test_uint64{fn: sub_uint64_18446744073709551615, fnname: "sub_uint64_18446744073709551615", in: 1, want: 2},
+ test_uint64{fn: sub_18446744073709551615_uint64, fnname: "sub_18446744073709551615_uint64", in: 4294967296, want: 18446744069414584319},
+ test_uint64{fn: sub_uint64_18446744073709551615, fnname: "sub_uint64_18446744073709551615", in: 4294967296, want: 4294967297},
+ test_uint64{fn: sub_18446744073709551615_uint64, fnname: "sub_18446744073709551615_uint64", in: 9223372036854775808, want: 9223372036854775807},
+ test_uint64{fn: sub_uint64_18446744073709551615, fnname: "sub_uint64_18446744073709551615", in: 9223372036854775808, want: 9223372036854775809},
+ test_uint64{fn: sub_18446744073709551615_uint64, fnname: "sub_18446744073709551615_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: sub_uint64_18446744073709551615, fnname: "sub_uint64_18446744073709551615", in: 18446744073709551615, want: 0},
+ test_uint64{fn: div_0_uint64, fnname: "div_0_uint64", in: 1, want: 0},
+ test_uint64{fn: div_0_uint64, fnname: "div_0_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: div_0_uint64, fnname: "div_0_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: div_0_uint64, fnname: "div_0_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: div_uint64_1, fnname: "div_uint64_1", in: 0, want: 0},
+ test_uint64{fn: div_1_uint64, fnname: "div_1_uint64", in: 1, want: 1},
+ test_uint64{fn: div_uint64_1, fnname: "div_uint64_1", in: 1, want: 1},
+ test_uint64{fn: div_1_uint64, fnname: "div_1_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: div_uint64_1, fnname: "div_uint64_1", in: 4294967296, want: 4294967296},
+ test_uint64{fn: div_1_uint64, fnname: "div_1_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: div_uint64_1, fnname: "div_uint64_1", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: div_1_uint64, fnname: "div_1_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: div_uint64_1, fnname: "div_uint64_1", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: div_uint64_4294967296, fnname: "div_uint64_4294967296", in: 0, want: 0},
+ test_uint64{fn: div_4294967296_uint64, fnname: "div_4294967296_uint64", in: 1, want: 4294967296},
+ test_uint64{fn: div_uint64_4294967296, fnname: "div_uint64_4294967296", in: 1, want: 0},
+ test_uint64{fn: div_4294967296_uint64, fnname: "div_4294967296_uint64", in: 4294967296, want: 1},
+ test_uint64{fn: div_uint64_4294967296, fnname: "div_uint64_4294967296", in: 4294967296, want: 1},
+ test_uint64{fn: div_4294967296_uint64, fnname: "div_4294967296_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: div_uint64_4294967296, fnname: "div_uint64_4294967296", in: 9223372036854775808, want: 2147483648},
+ test_uint64{fn: div_4294967296_uint64, fnname: "div_4294967296_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: div_uint64_4294967296, fnname: "div_uint64_4294967296", in: 18446744073709551615, want: 4294967295},
+ test_uint64{fn: div_uint64_9223372036854775808, fnname: "div_uint64_9223372036854775808", in: 0, want: 0},
+ test_uint64{fn: div_9223372036854775808_uint64, fnname: "div_9223372036854775808_uint64", in: 1, want: 9223372036854775808},
+ test_uint64{fn: div_uint64_9223372036854775808, fnname: "div_uint64_9223372036854775808", in: 1, want: 0},
+ test_uint64{fn: div_9223372036854775808_uint64, fnname: "div_9223372036854775808_uint64", in: 4294967296, want: 2147483648},
+ test_uint64{fn: div_uint64_9223372036854775808, fnname: "div_uint64_9223372036854775808", in: 4294967296, want: 0},
+ test_uint64{fn: div_9223372036854775808_uint64, fnname: "div_9223372036854775808_uint64", in: 9223372036854775808, want: 1},
+ test_uint64{fn: div_uint64_9223372036854775808, fnname: "div_uint64_9223372036854775808", in: 9223372036854775808, want: 1},
+ test_uint64{fn: div_9223372036854775808_uint64, fnname: "div_9223372036854775808_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: div_uint64_9223372036854775808, fnname: "div_uint64_9223372036854775808", in: 18446744073709551615, want: 1},
+ test_uint64{fn: div_uint64_18446744073709551615, fnname: "div_uint64_18446744073709551615", in: 0, want: 0},
+ test_uint64{fn: div_18446744073709551615_uint64, fnname: "div_18446744073709551615_uint64", in: 1, want: 18446744073709551615},
+ test_uint64{fn: div_uint64_18446744073709551615, fnname: "div_uint64_18446744073709551615", in: 1, want: 0},
+ test_uint64{fn: div_18446744073709551615_uint64, fnname: "div_18446744073709551615_uint64", in: 4294967296, want: 4294967295},
+ test_uint64{fn: div_uint64_18446744073709551615, fnname: "div_uint64_18446744073709551615", in: 4294967296, want: 0},
+ test_uint64{fn: div_18446744073709551615_uint64, fnname: "div_18446744073709551615_uint64", in: 9223372036854775808, want: 1},
+ test_uint64{fn: div_uint64_18446744073709551615, fnname: "div_uint64_18446744073709551615", in: 9223372036854775808, want: 0},
+ test_uint64{fn: div_18446744073709551615_uint64, fnname: "div_18446744073709551615_uint64", in: 18446744073709551615, want: 1},
+ test_uint64{fn: div_uint64_18446744073709551615, fnname: "div_uint64_18446744073709551615", in: 18446744073709551615, want: 1},
+ test_uint64{fn: mul_0_uint64, fnname: "mul_0_uint64", in: 0, want: 0},
+ test_uint64{fn: mul_uint64_0, fnname: "mul_uint64_0", in: 0, want: 0},
+ test_uint64{fn: mul_0_uint64, fnname: "mul_0_uint64", in: 1, want: 0},
+ test_uint64{fn: mul_uint64_0, fnname: "mul_uint64_0", in: 1, want: 0},
+ test_uint64{fn: mul_0_uint64, fnname: "mul_0_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: mul_uint64_0, fnname: "mul_uint64_0", in: 4294967296, want: 0},
+ test_uint64{fn: mul_0_uint64, fnname: "mul_0_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mul_uint64_0, fnname: "mul_uint64_0", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mul_0_uint64, fnname: "mul_0_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: mul_uint64_0, fnname: "mul_uint64_0", in: 18446744073709551615, want: 0},
+ test_uint64{fn: mul_1_uint64, fnname: "mul_1_uint64", in: 0, want: 0},
+ test_uint64{fn: mul_uint64_1, fnname: "mul_uint64_1", in: 0, want: 0},
+ test_uint64{fn: mul_1_uint64, fnname: "mul_1_uint64", in: 1, want: 1},
+ test_uint64{fn: mul_uint64_1, fnname: "mul_uint64_1", in: 1, want: 1},
+ test_uint64{fn: mul_1_uint64, fnname: "mul_1_uint64", in: 4294967296, want: 4294967296},
+ test_uint64{fn: mul_uint64_1, fnname: "mul_uint64_1", in: 4294967296, want: 4294967296},
+ test_uint64{fn: mul_1_uint64, fnname: "mul_1_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: mul_uint64_1, fnname: "mul_uint64_1", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: mul_1_uint64, fnname: "mul_1_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: mul_uint64_1, fnname: "mul_uint64_1", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: mul_4294967296_uint64, fnname: "mul_4294967296_uint64", in: 0, want: 0},
+ test_uint64{fn: mul_uint64_4294967296, fnname: "mul_uint64_4294967296", in: 0, want: 0},
+ test_uint64{fn: mul_4294967296_uint64, fnname: "mul_4294967296_uint64", in: 1, want: 4294967296},
+ test_uint64{fn: mul_uint64_4294967296, fnname: "mul_uint64_4294967296", in: 1, want: 4294967296},
+ test_uint64{fn: mul_4294967296_uint64, fnname: "mul_4294967296_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: mul_uint64_4294967296, fnname: "mul_uint64_4294967296", in: 4294967296, want: 0},
+ test_uint64{fn: mul_4294967296_uint64, fnname: "mul_4294967296_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mul_uint64_4294967296, fnname: "mul_uint64_4294967296", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mul_4294967296_uint64, fnname: "mul_4294967296_uint64", in: 18446744073709551615, want: 18446744069414584320},
+ test_uint64{fn: mul_uint64_4294967296, fnname: "mul_uint64_4294967296", in: 18446744073709551615, want: 18446744069414584320},
+ test_uint64{fn: mul_9223372036854775808_uint64, fnname: "mul_9223372036854775808_uint64", in: 0, want: 0},
+ test_uint64{fn: mul_uint64_9223372036854775808, fnname: "mul_uint64_9223372036854775808", in: 0, want: 0},
+ test_uint64{fn: mul_9223372036854775808_uint64, fnname: "mul_9223372036854775808_uint64", in: 1, want: 9223372036854775808},
+ test_uint64{fn: mul_uint64_9223372036854775808, fnname: "mul_uint64_9223372036854775808", in: 1, want: 9223372036854775808},
+ test_uint64{fn: mul_9223372036854775808_uint64, fnname: "mul_9223372036854775808_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: mul_uint64_9223372036854775808, fnname: "mul_uint64_9223372036854775808", in: 4294967296, want: 0},
+ test_uint64{fn: mul_9223372036854775808_uint64, fnname: "mul_9223372036854775808_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mul_uint64_9223372036854775808, fnname: "mul_uint64_9223372036854775808", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mul_9223372036854775808_uint64, fnname: "mul_9223372036854775808_uint64", in: 18446744073709551615, want: 9223372036854775808},
+ test_uint64{fn: mul_uint64_9223372036854775808, fnname: "mul_uint64_9223372036854775808", in: 18446744073709551615, want: 9223372036854775808},
+ test_uint64{fn: mul_18446744073709551615_uint64, fnname: "mul_18446744073709551615_uint64", in: 0, want: 0},
+ test_uint64{fn: mul_uint64_18446744073709551615, fnname: "mul_uint64_18446744073709551615", in: 0, want: 0},
+ test_uint64{fn: mul_18446744073709551615_uint64, fnname: "mul_18446744073709551615_uint64", in: 1, want: 18446744073709551615},
+ test_uint64{fn: mul_uint64_18446744073709551615, fnname: "mul_uint64_18446744073709551615", in: 1, want: 18446744073709551615},
+ test_uint64{fn: mul_18446744073709551615_uint64, fnname: "mul_18446744073709551615_uint64", in: 4294967296, want: 18446744069414584320},
+ test_uint64{fn: mul_uint64_18446744073709551615, fnname: "mul_uint64_18446744073709551615", in: 4294967296, want: 18446744069414584320},
+ test_uint64{fn: mul_18446744073709551615_uint64, fnname: "mul_18446744073709551615_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: mul_uint64_18446744073709551615, fnname: "mul_uint64_18446744073709551615", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: mul_18446744073709551615_uint64, fnname: "mul_18446744073709551615_uint64", in: 18446744073709551615, want: 1},
+ test_uint64{fn: mul_uint64_18446744073709551615, fnname: "mul_uint64_18446744073709551615", in: 18446744073709551615, want: 1},
+ test_uint64{fn: lsh_0_uint64, fnname: "lsh_0_uint64", in: 0, want: 0},
+ test_uint64{fn: lsh_uint64_0, fnname: "lsh_uint64_0", in: 0, want: 0},
+ test_uint64{fn: lsh_0_uint64, fnname: "lsh_0_uint64", in: 1, want: 0},
+ test_uint64{fn: lsh_uint64_0, fnname: "lsh_uint64_0", in: 1, want: 1},
+ test_uint64{fn: lsh_0_uint64, fnname: "lsh_0_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: lsh_uint64_0, fnname: "lsh_uint64_0", in: 4294967296, want: 4294967296},
+ test_uint64{fn: lsh_0_uint64, fnname: "lsh_0_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_uint64_0, fnname: "lsh_uint64_0", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: lsh_0_uint64, fnname: "lsh_0_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: lsh_uint64_0, fnname: "lsh_uint64_0", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: lsh_1_uint64, fnname: "lsh_1_uint64", in: 0, want: 1},
+ test_uint64{fn: lsh_uint64_1, fnname: "lsh_uint64_1", in: 0, want: 0},
+ test_uint64{fn: lsh_1_uint64, fnname: "lsh_1_uint64", in: 1, want: 2},
+ test_uint64{fn: lsh_uint64_1, fnname: "lsh_uint64_1", in: 1, want: 2},
+ test_uint64{fn: lsh_1_uint64, fnname: "lsh_1_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: lsh_uint64_1, fnname: "lsh_uint64_1", in: 4294967296, want: 8589934592},
+ test_uint64{fn: lsh_1_uint64, fnname: "lsh_1_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_uint64_1, fnname: "lsh_uint64_1", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_1_uint64, fnname: "lsh_1_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: lsh_uint64_1, fnname: "lsh_uint64_1", in: 18446744073709551615, want: 18446744073709551614},
+ test_uint64{fn: lsh_4294967296_uint64, fnname: "lsh_4294967296_uint64", in: 0, want: 4294967296},
+ test_uint64{fn: lsh_uint64_4294967296, fnname: "lsh_uint64_4294967296", in: 0, want: 0},
+ test_uint64{fn: lsh_4294967296_uint64, fnname: "lsh_4294967296_uint64", in: 1, want: 8589934592},
+ test_uint64{fn: lsh_uint64_4294967296, fnname: "lsh_uint64_4294967296", in: 1, want: 0},
+ test_uint64{fn: lsh_4294967296_uint64, fnname: "lsh_4294967296_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: lsh_uint64_4294967296, fnname: "lsh_uint64_4294967296", in: 4294967296, want: 0},
+ test_uint64{fn: lsh_4294967296_uint64, fnname: "lsh_4294967296_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_uint64_4294967296, fnname: "lsh_uint64_4294967296", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_4294967296_uint64, fnname: "lsh_4294967296_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: lsh_uint64_4294967296, fnname: "lsh_uint64_4294967296", in: 18446744073709551615, want: 0},
+ test_uint64{fn: lsh_9223372036854775808_uint64, fnname: "lsh_9223372036854775808_uint64", in: 0, want: 9223372036854775808},
+ test_uint64{fn: lsh_uint64_9223372036854775808, fnname: "lsh_uint64_9223372036854775808", in: 0, want: 0},
+ test_uint64{fn: lsh_9223372036854775808_uint64, fnname: "lsh_9223372036854775808_uint64", in: 1, want: 0},
+ test_uint64{fn: lsh_uint64_9223372036854775808, fnname: "lsh_uint64_9223372036854775808", in: 1, want: 0},
+ test_uint64{fn: lsh_9223372036854775808_uint64, fnname: "lsh_9223372036854775808_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: lsh_uint64_9223372036854775808, fnname: "lsh_uint64_9223372036854775808", in: 4294967296, want: 0},
+ test_uint64{fn: lsh_9223372036854775808_uint64, fnname: "lsh_9223372036854775808_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_uint64_9223372036854775808, fnname: "lsh_uint64_9223372036854775808", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_9223372036854775808_uint64, fnname: "lsh_9223372036854775808_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: lsh_uint64_9223372036854775808, fnname: "lsh_uint64_9223372036854775808", in: 18446744073709551615, want: 0},
+ test_uint64{fn: lsh_18446744073709551615_uint64, fnname: "lsh_18446744073709551615_uint64", in: 0, want: 18446744073709551615},
+ test_uint64{fn: lsh_uint64_18446744073709551615, fnname: "lsh_uint64_18446744073709551615", in: 0, want: 0},
+ test_uint64{fn: lsh_18446744073709551615_uint64, fnname: "lsh_18446744073709551615_uint64", in: 1, want: 18446744073709551614},
+ test_uint64{fn: lsh_uint64_18446744073709551615, fnname: "lsh_uint64_18446744073709551615", in: 1, want: 0},
+ test_uint64{fn: lsh_18446744073709551615_uint64, fnname: "lsh_18446744073709551615_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: lsh_uint64_18446744073709551615, fnname: "lsh_uint64_18446744073709551615", in: 4294967296, want: 0},
+ test_uint64{fn: lsh_18446744073709551615_uint64, fnname: "lsh_18446744073709551615_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_uint64_18446744073709551615, fnname: "lsh_uint64_18446744073709551615", in: 9223372036854775808, want: 0},
+ test_uint64{fn: lsh_18446744073709551615_uint64, fnname: "lsh_18446744073709551615_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: lsh_uint64_18446744073709551615, fnname: "lsh_uint64_18446744073709551615", in: 18446744073709551615, want: 0},
+ test_uint64{fn: rsh_0_uint64, fnname: "rsh_0_uint64", in: 0, want: 0},
+ test_uint64{fn: rsh_uint64_0, fnname: "rsh_uint64_0", in: 0, want: 0},
+ test_uint64{fn: rsh_0_uint64, fnname: "rsh_0_uint64", in: 1, want: 0},
+ test_uint64{fn: rsh_uint64_0, fnname: "rsh_uint64_0", in: 1, want: 1},
+ test_uint64{fn: rsh_0_uint64, fnname: "rsh_0_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: rsh_uint64_0, fnname: "rsh_uint64_0", in: 4294967296, want: 4294967296},
+ test_uint64{fn: rsh_0_uint64, fnname: "rsh_0_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: rsh_uint64_0, fnname: "rsh_uint64_0", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: rsh_0_uint64, fnname: "rsh_0_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: rsh_uint64_0, fnname: "rsh_uint64_0", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: rsh_1_uint64, fnname: "rsh_1_uint64", in: 0, want: 1},
+ test_uint64{fn: rsh_uint64_1, fnname: "rsh_uint64_1", in: 0, want: 0},
+ test_uint64{fn: rsh_1_uint64, fnname: "rsh_1_uint64", in: 1, want: 0},
+ test_uint64{fn: rsh_uint64_1, fnname: "rsh_uint64_1", in: 1, want: 0},
+ test_uint64{fn: rsh_1_uint64, fnname: "rsh_1_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: rsh_uint64_1, fnname: "rsh_uint64_1", in: 4294967296, want: 2147483648},
+ test_uint64{fn: rsh_1_uint64, fnname: "rsh_1_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: rsh_uint64_1, fnname: "rsh_uint64_1", in: 9223372036854775808, want: 4611686018427387904},
+ test_uint64{fn: rsh_1_uint64, fnname: "rsh_1_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: rsh_uint64_1, fnname: "rsh_uint64_1", in: 18446744073709551615, want: 9223372036854775807},
+ test_uint64{fn: rsh_4294967296_uint64, fnname: "rsh_4294967296_uint64", in: 0, want: 4294967296},
+ test_uint64{fn: rsh_uint64_4294967296, fnname: "rsh_uint64_4294967296", in: 0, want: 0},
+ test_uint64{fn: rsh_4294967296_uint64, fnname: "rsh_4294967296_uint64", in: 1, want: 2147483648},
+ test_uint64{fn: rsh_uint64_4294967296, fnname: "rsh_uint64_4294967296", in: 1, want: 0},
+ test_uint64{fn: rsh_4294967296_uint64, fnname: "rsh_4294967296_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: rsh_uint64_4294967296, fnname: "rsh_uint64_4294967296", in: 4294967296, want: 0},
+ test_uint64{fn: rsh_4294967296_uint64, fnname: "rsh_4294967296_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: rsh_uint64_4294967296, fnname: "rsh_uint64_4294967296", in: 9223372036854775808, want: 0},
+ test_uint64{fn: rsh_4294967296_uint64, fnname: "rsh_4294967296_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: rsh_uint64_4294967296, fnname: "rsh_uint64_4294967296", in: 18446744073709551615, want: 0},
+ test_uint64{fn: rsh_9223372036854775808_uint64, fnname: "rsh_9223372036854775808_uint64", in: 0, want: 9223372036854775808},
+ test_uint64{fn: rsh_uint64_9223372036854775808, fnname: "rsh_uint64_9223372036854775808", in: 0, want: 0},
+ test_uint64{fn: rsh_9223372036854775808_uint64, fnname: "rsh_9223372036854775808_uint64", in: 1, want: 4611686018427387904},
+ test_uint64{fn: rsh_uint64_9223372036854775808, fnname: "rsh_uint64_9223372036854775808", in: 1, want: 0},
+ test_uint64{fn: rsh_9223372036854775808_uint64, fnname: "rsh_9223372036854775808_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: rsh_uint64_9223372036854775808, fnname: "rsh_uint64_9223372036854775808", in: 4294967296, want: 0},
+ test_uint64{fn: rsh_9223372036854775808_uint64, fnname: "rsh_9223372036854775808_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: rsh_uint64_9223372036854775808, fnname: "rsh_uint64_9223372036854775808", in: 9223372036854775808, want: 0},
+ test_uint64{fn: rsh_9223372036854775808_uint64, fnname: "rsh_9223372036854775808_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: rsh_uint64_9223372036854775808, fnname: "rsh_uint64_9223372036854775808", in: 18446744073709551615, want: 0},
+ test_uint64{fn: rsh_18446744073709551615_uint64, fnname: "rsh_18446744073709551615_uint64", in: 0, want: 18446744073709551615},
+ test_uint64{fn: rsh_uint64_18446744073709551615, fnname: "rsh_uint64_18446744073709551615", in: 0, want: 0},
+ test_uint64{fn: rsh_18446744073709551615_uint64, fnname: "rsh_18446744073709551615_uint64", in: 1, want: 9223372036854775807},
+ test_uint64{fn: rsh_uint64_18446744073709551615, fnname: "rsh_uint64_18446744073709551615", in: 1, want: 0},
+ test_uint64{fn: rsh_18446744073709551615_uint64, fnname: "rsh_18446744073709551615_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: rsh_uint64_18446744073709551615, fnname: "rsh_uint64_18446744073709551615", in: 4294967296, want: 0},
+ test_uint64{fn: rsh_18446744073709551615_uint64, fnname: "rsh_18446744073709551615_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: rsh_uint64_18446744073709551615, fnname: "rsh_uint64_18446744073709551615", in: 9223372036854775808, want: 0},
+ test_uint64{fn: rsh_18446744073709551615_uint64, fnname: "rsh_18446744073709551615_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: rsh_uint64_18446744073709551615, fnname: "rsh_uint64_18446744073709551615", in: 18446744073709551615, want: 0},
+ test_uint64{fn: mod_0_uint64, fnname: "mod_0_uint64", in: 1, want: 0},
+ test_uint64{fn: mod_0_uint64, fnname: "mod_0_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: mod_0_uint64, fnname: "mod_0_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mod_0_uint64, fnname: "mod_0_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: mod_uint64_1, fnname: "mod_uint64_1", in: 0, want: 0},
+ test_uint64{fn: mod_1_uint64, fnname: "mod_1_uint64", in: 1, want: 0},
+ test_uint64{fn: mod_uint64_1, fnname: "mod_uint64_1", in: 1, want: 0},
+ test_uint64{fn: mod_1_uint64, fnname: "mod_1_uint64", in: 4294967296, want: 1},
+ test_uint64{fn: mod_uint64_1, fnname: "mod_uint64_1", in: 4294967296, want: 0},
+ test_uint64{fn: mod_1_uint64, fnname: "mod_1_uint64", in: 9223372036854775808, want: 1},
+ test_uint64{fn: mod_uint64_1, fnname: "mod_uint64_1", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mod_1_uint64, fnname: "mod_1_uint64", in: 18446744073709551615, want: 1},
+ test_uint64{fn: mod_uint64_1, fnname: "mod_uint64_1", in: 18446744073709551615, want: 0},
+ test_uint64{fn: mod_uint64_4294967296, fnname: "mod_uint64_4294967296", in: 0, want: 0},
+ test_uint64{fn: mod_4294967296_uint64, fnname: "mod_4294967296_uint64", in: 1, want: 0},
+ test_uint64{fn: mod_uint64_4294967296, fnname: "mod_uint64_4294967296", in: 1, want: 1},
+ test_uint64{fn: mod_4294967296_uint64, fnname: "mod_4294967296_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: mod_uint64_4294967296, fnname: "mod_uint64_4294967296", in: 4294967296, want: 0},
+ test_uint64{fn: mod_4294967296_uint64, fnname: "mod_4294967296_uint64", in: 9223372036854775808, want: 4294967296},
+ test_uint64{fn: mod_uint64_4294967296, fnname: "mod_uint64_4294967296", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mod_4294967296_uint64, fnname: "mod_4294967296_uint64", in: 18446744073709551615, want: 4294967296},
+ test_uint64{fn: mod_uint64_4294967296, fnname: "mod_uint64_4294967296", in: 18446744073709551615, want: 4294967295},
+ test_uint64{fn: mod_uint64_9223372036854775808, fnname: "mod_uint64_9223372036854775808", in: 0, want: 0},
+ test_uint64{fn: mod_9223372036854775808_uint64, fnname: "mod_9223372036854775808_uint64", in: 1, want: 0},
+ test_uint64{fn: mod_uint64_9223372036854775808, fnname: "mod_uint64_9223372036854775808", in: 1, want: 1},
+ test_uint64{fn: mod_9223372036854775808_uint64, fnname: "mod_9223372036854775808_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: mod_uint64_9223372036854775808, fnname: "mod_uint64_9223372036854775808", in: 4294967296, want: 4294967296},
+ test_uint64{fn: mod_9223372036854775808_uint64, fnname: "mod_9223372036854775808_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mod_uint64_9223372036854775808, fnname: "mod_uint64_9223372036854775808", in: 9223372036854775808, want: 0},
+ test_uint64{fn: mod_9223372036854775808_uint64, fnname: "mod_9223372036854775808_uint64", in: 18446744073709551615, want: 9223372036854775808},
+ test_uint64{fn: mod_uint64_9223372036854775808, fnname: "mod_uint64_9223372036854775808", in: 18446744073709551615, want: 9223372036854775807},
+ test_uint64{fn: mod_uint64_18446744073709551615, fnname: "mod_uint64_18446744073709551615", in: 0, want: 0},
+ test_uint64{fn: mod_18446744073709551615_uint64, fnname: "mod_18446744073709551615_uint64", in: 1, want: 0},
+ test_uint64{fn: mod_uint64_18446744073709551615, fnname: "mod_uint64_18446744073709551615", in: 1, want: 1},
+ test_uint64{fn: mod_18446744073709551615_uint64, fnname: "mod_18446744073709551615_uint64", in: 4294967296, want: 4294967295},
+ test_uint64{fn: mod_uint64_18446744073709551615, fnname: "mod_uint64_18446744073709551615", in: 4294967296, want: 4294967296},
+ test_uint64{fn: mod_18446744073709551615_uint64, fnname: "mod_18446744073709551615_uint64", in: 9223372036854775808, want: 9223372036854775807},
+ test_uint64{fn: mod_uint64_18446744073709551615, fnname: "mod_uint64_18446744073709551615", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: mod_18446744073709551615_uint64, fnname: "mod_18446744073709551615_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: mod_uint64_18446744073709551615, fnname: "mod_uint64_18446744073709551615", in: 18446744073709551615, want: 0},
+ test_uint64{fn: and_0_uint64, fnname: "and_0_uint64", in: 0, want: 0},
+ test_uint64{fn: and_uint64_0, fnname: "and_uint64_0", in: 0, want: 0},
+ test_uint64{fn: and_0_uint64, fnname: "and_0_uint64", in: 1, want: 0},
+ test_uint64{fn: and_uint64_0, fnname: "and_uint64_0", in: 1, want: 0},
+ test_uint64{fn: and_0_uint64, fnname: "and_0_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: and_uint64_0, fnname: "and_uint64_0", in: 4294967296, want: 0},
+ test_uint64{fn: and_0_uint64, fnname: "and_0_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: and_uint64_0, fnname: "and_uint64_0", in: 9223372036854775808, want: 0},
+ test_uint64{fn: and_0_uint64, fnname: "and_0_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: and_uint64_0, fnname: "and_uint64_0", in: 18446744073709551615, want: 0},
+ test_uint64{fn: and_1_uint64, fnname: "and_1_uint64", in: 0, want: 0},
+ test_uint64{fn: and_uint64_1, fnname: "and_uint64_1", in: 0, want: 0},
+ test_uint64{fn: and_1_uint64, fnname: "and_1_uint64", in: 1, want: 1},
+ test_uint64{fn: and_uint64_1, fnname: "and_uint64_1", in: 1, want: 1},
+ test_uint64{fn: and_1_uint64, fnname: "and_1_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: and_uint64_1, fnname: "and_uint64_1", in: 4294967296, want: 0},
+ test_uint64{fn: and_1_uint64, fnname: "and_1_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: and_uint64_1, fnname: "and_uint64_1", in: 9223372036854775808, want: 0},
+ test_uint64{fn: and_1_uint64, fnname: "and_1_uint64", in: 18446744073709551615, want: 1},
+ test_uint64{fn: and_uint64_1, fnname: "and_uint64_1", in: 18446744073709551615, want: 1},
+ test_uint64{fn: and_4294967296_uint64, fnname: "and_4294967296_uint64", in: 0, want: 0},
+ test_uint64{fn: and_uint64_4294967296, fnname: "and_uint64_4294967296", in: 0, want: 0},
+ test_uint64{fn: and_4294967296_uint64, fnname: "and_4294967296_uint64", in: 1, want: 0},
+ test_uint64{fn: and_uint64_4294967296, fnname: "and_uint64_4294967296", in: 1, want: 0},
+ test_uint64{fn: and_4294967296_uint64, fnname: "and_4294967296_uint64", in: 4294967296, want: 4294967296},
+ test_uint64{fn: and_uint64_4294967296, fnname: "and_uint64_4294967296", in: 4294967296, want: 4294967296},
+ test_uint64{fn: and_4294967296_uint64, fnname: "and_4294967296_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: and_uint64_4294967296, fnname: "and_uint64_4294967296", in: 9223372036854775808, want: 0},
+ test_uint64{fn: and_4294967296_uint64, fnname: "and_4294967296_uint64", in: 18446744073709551615, want: 4294967296},
+ test_uint64{fn: and_uint64_4294967296, fnname: "and_uint64_4294967296", in: 18446744073709551615, want: 4294967296},
+ test_uint64{fn: and_9223372036854775808_uint64, fnname: "and_9223372036854775808_uint64", in: 0, want: 0},
+ test_uint64{fn: and_uint64_9223372036854775808, fnname: "and_uint64_9223372036854775808", in: 0, want: 0},
+ test_uint64{fn: and_9223372036854775808_uint64, fnname: "and_9223372036854775808_uint64", in: 1, want: 0},
+ test_uint64{fn: and_uint64_9223372036854775808, fnname: "and_uint64_9223372036854775808", in: 1, want: 0},
+ test_uint64{fn: and_9223372036854775808_uint64, fnname: "and_9223372036854775808_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: and_uint64_9223372036854775808, fnname: "and_uint64_9223372036854775808", in: 4294967296, want: 0},
+ test_uint64{fn: and_9223372036854775808_uint64, fnname: "and_9223372036854775808_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: and_uint64_9223372036854775808, fnname: "and_uint64_9223372036854775808", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: and_9223372036854775808_uint64, fnname: "and_9223372036854775808_uint64", in: 18446744073709551615, want: 9223372036854775808},
+ test_uint64{fn: and_uint64_9223372036854775808, fnname: "and_uint64_9223372036854775808", in: 18446744073709551615, want: 9223372036854775808},
+ test_uint64{fn: and_18446744073709551615_uint64, fnname: "and_18446744073709551615_uint64", in: 0, want: 0},
+ test_uint64{fn: and_uint64_18446744073709551615, fnname: "and_uint64_18446744073709551615", in: 0, want: 0},
+ test_uint64{fn: and_18446744073709551615_uint64, fnname: "and_18446744073709551615_uint64", in: 1, want: 1},
+ test_uint64{fn: and_uint64_18446744073709551615, fnname: "and_uint64_18446744073709551615", in: 1, want: 1},
+ test_uint64{fn: and_18446744073709551615_uint64, fnname: "and_18446744073709551615_uint64", in: 4294967296, want: 4294967296},
+ test_uint64{fn: and_uint64_18446744073709551615, fnname: "and_uint64_18446744073709551615", in: 4294967296, want: 4294967296},
+ test_uint64{fn: and_18446744073709551615_uint64, fnname: "and_18446744073709551615_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: and_uint64_18446744073709551615, fnname: "and_uint64_18446744073709551615", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: and_18446744073709551615_uint64, fnname: "and_18446744073709551615_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: and_uint64_18446744073709551615, fnname: "and_uint64_18446744073709551615", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_0_uint64, fnname: "or_0_uint64", in: 0, want: 0},
+ test_uint64{fn: or_uint64_0, fnname: "or_uint64_0", in: 0, want: 0},
+ test_uint64{fn: or_0_uint64, fnname: "or_0_uint64", in: 1, want: 1},
+ test_uint64{fn: or_uint64_0, fnname: "or_uint64_0", in: 1, want: 1},
+ test_uint64{fn: or_0_uint64, fnname: "or_0_uint64", in: 4294967296, want: 4294967296},
+ test_uint64{fn: or_uint64_0, fnname: "or_uint64_0", in: 4294967296, want: 4294967296},
+ test_uint64{fn: or_0_uint64, fnname: "or_0_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: or_uint64_0, fnname: "or_uint64_0", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: or_0_uint64, fnname: "or_0_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_0, fnname: "or_uint64_0", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_1_uint64, fnname: "or_1_uint64", in: 0, want: 1},
+ test_uint64{fn: or_uint64_1, fnname: "or_uint64_1", in: 0, want: 1},
+ test_uint64{fn: or_1_uint64, fnname: "or_1_uint64", in: 1, want: 1},
+ test_uint64{fn: or_uint64_1, fnname: "or_uint64_1", in: 1, want: 1},
+ test_uint64{fn: or_1_uint64, fnname: "or_1_uint64", in: 4294967296, want: 4294967297},
+ test_uint64{fn: or_uint64_1, fnname: "or_uint64_1", in: 4294967296, want: 4294967297},
+ test_uint64{fn: or_1_uint64, fnname: "or_1_uint64", in: 9223372036854775808, want: 9223372036854775809},
+ test_uint64{fn: or_uint64_1, fnname: "or_uint64_1", in: 9223372036854775808, want: 9223372036854775809},
+ test_uint64{fn: or_1_uint64, fnname: "or_1_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_1, fnname: "or_uint64_1", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_4294967296_uint64, fnname: "or_4294967296_uint64", in: 0, want: 4294967296},
+ test_uint64{fn: or_uint64_4294967296, fnname: "or_uint64_4294967296", in: 0, want: 4294967296},
+ test_uint64{fn: or_4294967296_uint64, fnname: "or_4294967296_uint64", in: 1, want: 4294967297},
+ test_uint64{fn: or_uint64_4294967296, fnname: "or_uint64_4294967296", in: 1, want: 4294967297},
+ test_uint64{fn: or_4294967296_uint64, fnname: "or_4294967296_uint64", in: 4294967296, want: 4294967296},
+ test_uint64{fn: or_uint64_4294967296, fnname: "or_uint64_4294967296", in: 4294967296, want: 4294967296},
+ test_uint64{fn: or_4294967296_uint64, fnname: "or_4294967296_uint64", in: 9223372036854775808, want: 9223372041149743104},
+ test_uint64{fn: or_uint64_4294967296, fnname: "or_uint64_4294967296", in: 9223372036854775808, want: 9223372041149743104},
+ test_uint64{fn: or_4294967296_uint64, fnname: "or_4294967296_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_4294967296, fnname: "or_uint64_4294967296", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_9223372036854775808_uint64, fnname: "or_9223372036854775808_uint64", in: 0, want: 9223372036854775808},
+ test_uint64{fn: or_uint64_9223372036854775808, fnname: "or_uint64_9223372036854775808", in: 0, want: 9223372036854775808},
+ test_uint64{fn: or_9223372036854775808_uint64, fnname: "or_9223372036854775808_uint64", in: 1, want: 9223372036854775809},
+ test_uint64{fn: or_uint64_9223372036854775808, fnname: "or_uint64_9223372036854775808", in: 1, want: 9223372036854775809},
+ test_uint64{fn: or_9223372036854775808_uint64, fnname: "or_9223372036854775808_uint64", in: 4294967296, want: 9223372041149743104},
+ test_uint64{fn: or_uint64_9223372036854775808, fnname: "or_uint64_9223372036854775808", in: 4294967296, want: 9223372041149743104},
+ test_uint64{fn: or_9223372036854775808_uint64, fnname: "or_9223372036854775808_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: or_uint64_9223372036854775808, fnname: "or_uint64_9223372036854775808", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: or_9223372036854775808_uint64, fnname: "or_9223372036854775808_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_9223372036854775808, fnname: "or_uint64_9223372036854775808", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_18446744073709551615_uint64, fnname: "or_18446744073709551615_uint64", in: 0, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_18446744073709551615, fnname: "or_uint64_18446744073709551615", in: 0, want: 18446744073709551615},
+ test_uint64{fn: or_18446744073709551615_uint64, fnname: "or_18446744073709551615_uint64", in: 1, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_18446744073709551615, fnname: "or_uint64_18446744073709551615", in: 1, want: 18446744073709551615},
+ test_uint64{fn: or_18446744073709551615_uint64, fnname: "or_18446744073709551615_uint64", in: 4294967296, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_18446744073709551615, fnname: "or_uint64_18446744073709551615", in: 4294967296, want: 18446744073709551615},
+ test_uint64{fn: or_18446744073709551615_uint64, fnname: "or_18446744073709551615_uint64", in: 9223372036854775808, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_18446744073709551615, fnname: "or_uint64_18446744073709551615", in: 9223372036854775808, want: 18446744073709551615},
+ test_uint64{fn: or_18446744073709551615_uint64, fnname: "or_18446744073709551615_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: or_uint64_18446744073709551615, fnname: "or_uint64_18446744073709551615", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: xor_0_uint64, fnname: "xor_0_uint64", in: 0, want: 0},
+ test_uint64{fn: xor_uint64_0, fnname: "xor_uint64_0", in: 0, want: 0},
+ test_uint64{fn: xor_0_uint64, fnname: "xor_0_uint64", in: 1, want: 1},
+ test_uint64{fn: xor_uint64_0, fnname: "xor_uint64_0", in: 1, want: 1},
+ test_uint64{fn: xor_0_uint64, fnname: "xor_0_uint64", in: 4294967296, want: 4294967296},
+ test_uint64{fn: xor_uint64_0, fnname: "xor_uint64_0", in: 4294967296, want: 4294967296},
+ test_uint64{fn: xor_0_uint64, fnname: "xor_0_uint64", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: xor_uint64_0, fnname: "xor_uint64_0", in: 9223372036854775808, want: 9223372036854775808},
+ test_uint64{fn: xor_0_uint64, fnname: "xor_0_uint64", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: xor_uint64_0, fnname: "xor_uint64_0", in: 18446744073709551615, want: 18446744073709551615},
+ test_uint64{fn: xor_1_uint64, fnname: "xor_1_uint64", in: 0, want: 1},
+ test_uint64{fn: xor_uint64_1, fnname: "xor_uint64_1", in: 0, want: 1},
+ test_uint64{fn: xor_1_uint64, fnname: "xor_1_uint64", in: 1, want: 0},
+ test_uint64{fn: xor_uint64_1, fnname: "xor_uint64_1", in: 1, want: 0},
+ test_uint64{fn: xor_1_uint64, fnname: "xor_1_uint64", in: 4294967296, want: 4294967297},
+ test_uint64{fn: xor_uint64_1, fnname: "xor_uint64_1", in: 4294967296, want: 4294967297},
+ test_uint64{fn: xor_1_uint64, fnname: "xor_1_uint64", in: 9223372036854775808, want: 9223372036854775809},
+ test_uint64{fn: xor_uint64_1, fnname: "xor_uint64_1", in: 9223372036854775808, want: 9223372036854775809},
+ test_uint64{fn: xor_1_uint64, fnname: "xor_1_uint64", in: 18446744073709551615, want: 18446744073709551614},
+ test_uint64{fn: xor_uint64_1, fnname: "xor_uint64_1", in: 18446744073709551615, want: 18446744073709551614},
+ test_uint64{fn: xor_4294967296_uint64, fnname: "xor_4294967296_uint64", in: 0, want: 4294967296},
+ test_uint64{fn: xor_uint64_4294967296, fnname: "xor_uint64_4294967296", in: 0, want: 4294967296},
+ test_uint64{fn: xor_4294967296_uint64, fnname: "xor_4294967296_uint64", in: 1, want: 4294967297},
+ test_uint64{fn: xor_uint64_4294967296, fnname: "xor_uint64_4294967296", in: 1, want: 4294967297},
+ test_uint64{fn: xor_4294967296_uint64, fnname: "xor_4294967296_uint64", in: 4294967296, want: 0},
+ test_uint64{fn: xor_uint64_4294967296, fnname: "xor_uint64_4294967296", in: 4294967296, want: 0},
+ test_uint64{fn: xor_4294967296_uint64, fnname: "xor_4294967296_uint64", in: 9223372036854775808, want: 9223372041149743104},
+ test_uint64{fn: xor_uint64_4294967296, fnname: "xor_uint64_4294967296", in: 9223372036854775808, want: 9223372041149743104},
+ test_uint64{fn: xor_4294967296_uint64, fnname: "xor_4294967296_uint64", in: 18446744073709551615, want: 18446744069414584319},
+ test_uint64{fn: xor_uint64_4294967296, fnname: "xor_uint64_4294967296", in: 18446744073709551615, want: 18446744069414584319},
+ test_uint64{fn: xor_9223372036854775808_uint64, fnname: "xor_9223372036854775808_uint64", in: 0, want: 9223372036854775808},
+ test_uint64{fn: xor_uint64_9223372036854775808, fnname: "xor_uint64_9223372036854775808", in: 0, want: 9223372036854775808},
+ test_uint64{fn: xor_9223372036854775808_uint64, fnname: "xor_9223372036854775808_uint64", in: 1, want: 9223372036854775809},
+ test_uint64{fn: xor_uint64_9223372036854775808, fnname: "xor_uint64_9223372036854775808", in: 1, want: 9223372036854775809},
+ test_uint64{fn: xor_9223372036854775808_uint64, fnname: "xor_9223372036854775808_uint64", in: 4294967296, want: 9223372041149743104},
+ test_uint64{fn: xor_uint64_9223372036854775808, fnname: "xor_uint64_9223372036854775808", in: 4294967296, want: 9223372041149743104},
+ test_uint64{fn: xor_9223372036854775808_uint64, fnname: "xor_9223372036854775808_uint64", in: 9223372036854775808, want: 0},
+ test_uint64{fn: xor_uint64_9223372036854775808, fnname: "xor_uint64_9223372036854775808", in: 9223372036854775808, want: 0},
+ test_uint64{fn: xor_9223372036854775808_uint64, fnname: "xor_9223372036854775808_uint64", in: 18446744073709551615, want: 9223372036854775807},
+ test_uint64{fn: xor_uint64_9223372036854775808, fnname: "xor_uint64_9223372036854775808", in: 18446744073709551615, want: 9223372036854775807},
+ test_uint64{fn: xor_18446744073709551615_uint64, fnname: "xor_18446744073709551615_uint64", in: 0, want: 18446744073709551615},
+ test_uint64{fn: xor_uint64_18446744073709551615, fnname: "xor_uint64_18446744073709551615", in: 0, want: 18446744073709551615},
+ test_uint64{fn: xor_18446744073709551615_uint64, fnname: "xor_18446744073709551615_uint64", in: 1, want: 18446744073709551614},
+ test_uint64{fn: xor_uint64_18446744073709551615, fnname: "xor_uint64_18446744073709551615", in: 1, want: 18446744073709551614},
+ test_uint64{fn: xor_18446744073709551615_uint64, fnname: "xor_18446744073709551615_uint64", in: 4294967296, want: 18446744069414584319},
+ test_uint64{fn: xor_uint64_18446744073709551615, fnname: "xor_uint64_18446744073709551615", in: 4294967296, want: 18446744069414584319},
+ test_uint64{fn: xor_18446744073709551615_uint64, fnname: "xor_18446744073709551615_uint64", in: 9223372036854775808, want: 9223372036854775807},
+ test_uint64{fn: xor_uint64_18446744073709551615, fnname: "xor_uint64_18446744073709551615", in: 9223372036854775808, want: 9223372036854775807},
+ test_uint64{fn: xor_18446744073709551615_uint64, fnname: "xor_18446744073709551615_uint64", in: 18446744073709551615, want: 0},
+ test_uint64{fn: xor_uint64_18446744073709551615, fnname: "xor_uint64_18446744073709551615", in: 18446744073709551615, want: 0}}
+
+type test_uint64mul struct {
+ fn func(uint64) uint64
+ fnname string
+ in uint64
+ want uint64
+}
+
+var tests_uint64mul = []test_uint64{
+
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 3, want: 9},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 3, want: 9},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 5, want: 15},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 5, want: 15},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 7, want: 21},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 7, want: 21},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 9, want: 27},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 9, want: 27},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 10, want: 30},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 10, want: 30},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 11, want: 33},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 11, want: 33},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 13, want: 39},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 13, want: 39},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 19, want: 57},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 19, want: 57},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 21, want: 63},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 21, want: 63},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 25, want: 75},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 25, want: 75},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 27, want: 81},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 27, want: 81},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 37, want: 111},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 37, want: 111},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 41, want: 123},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 41, want: 123},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 45, want: 135},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 45, want: 135},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 73, want: 219},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 73, want: 219},
+ test_uint64{fn: mul_3_uint64, fnname: "mul_3_uint64", in: 81, want: 243},
+ test_uint64{fn: mul_uint64_3, fnname: "mul_uint64_3", in: 81, want: 243},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 3, want: 15},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 3, want: 15},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 5, want: 25},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 5, want: 25},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 7, want: 35},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 7, want: 35},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 9, want: 45},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 9, want: 45},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 10, want: 50},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 10, want: 50},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 11, want: 55},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 11, want: 55},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 13, want: 65},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 13, want: 65},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 19, want: 95},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 19, want: 95},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 21, want: 105},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 21, want: 105},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 25, want: 125},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 25, want: 125},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 27, want: 135},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 27, want: 135},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 37, want: 185},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 37, want: 185},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 41, want: 205},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 41, want: 205},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 45, want: 225},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 45, want: 225},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 73, want: 365},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 73, want: 365},
+ test_uint64{fn: mul_5_uint64, fnname: "mul_5_uint64", in: 81, want: 405},
+ test_uint64{fn: mul_uint64_5, fnname: "mul_uint64_5", in: 81, want: 405},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 3, want: 21},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 3, want: 21},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 5, want: 35},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 5, want: 35},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 7, want: 49},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 7, want: 49},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 9, want: 63},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 9, want: 63},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 10, want: 70},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 10, want: 70},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 11, want: 77},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 11, want: 77},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 13, want: 91},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 13, want: 91},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 19, want: 133},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 19, want: 133},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 21, want: 147},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 21, want: 147},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 25, want: 175},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 25, want: 175},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 27, want: 189},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 27, want: 189},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 37, want: 259},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 37, want: 259},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 41, want: 287},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 41, want: 287},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 45, want: 315},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 45, want: 315},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 73, want: 511},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 73, want: 511},
+ test_uint64{fn: mul_7_uint64, fnname: "mul_7_uint64", in: 81, want: 567},
+ test_uint64{fn: mul_uint64_7, fnname: "mul_uint64_7", in: 81, want: 567},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 3, want: 27},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 3, want: 27},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 5, want: 45},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 5, want: 45},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 7, want: 63},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 7, want: 63},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 9, want: 81},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 9, want: 81},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 10, want: 90},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 10, want: 90},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 11, want: 99},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 11, want: 99},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 13, want: 117},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 13, want: 117},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 19, want: 171},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 19, want: 171},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 21, want: 189},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 21, want: 189},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 25, want: 225},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 25, want: 225},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 27, want: 243},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 27, want: 243},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 37, want: 333},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 37, want: 333},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 41, want: 369},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 41, want: 369},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 45, want: 405},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 45, want: 405},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 73, want: 657},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 73, want: 657},
+ test_uint64{fn: mul_9_uint64, fnname: "mul_9_uint64", in: 81, want: 729},
+ test_uint64{fn: mul_uint64_9, fnname: "mul_uint64_9", in: 81, want: 729},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 3, want: 30},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 3, want: 30},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 5, want: 50},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 5, want: 50},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 7, want: 70},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 7, want: 70},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 9, want: 90},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 9, want: 90},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 10, want: 100},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 10, want: 100},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 11, want: 110},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 11, want: 110},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 13, want: 130},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 13, want: 130},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 19, want: 190},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 19, want: 190},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 21, want: 210},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 21, want: 210},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 25, want: 250},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 25, want: 250},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 27, want: 270},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 27, want: 270},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 37, want: 370},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 37, want: 370},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 41, want: 410},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 41, want: 410},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 45, want: 450},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 45, want: 450},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 73, want: 730},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 73, want: 730},
+ test_uint64{fn: mul_10_uint64, fnname: "mul_10_uint64", in: 81, want: 810},
+ test_uint64{fn: mul_uint64_10, fnname: "mul_uint64_10", in: 81, want: 810},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 3, want: 33},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 3, want: 33},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 5, want: 55},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 5, want: 55},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 7, want: 77},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 7, want: 77},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 9, want: 99},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 9, want: 99},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 10, want: 110},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 10, want: 110},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 11, want: 121},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 11, want: 121},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 13, want: 143},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 13, want: 143},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 19, want: 209},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 19, want: 209},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 21, want: 231},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 21, want: 231},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 25, want: 275},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 25, want: 275},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 27, want: 297},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 27, want: 297},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 37, want: 407},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 37, want: 407},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 41, want: 451},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 41, want: 451},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 45, want: 495},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 45, want: 495},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 73, want: 803},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 73, want: 803},
+ test_uint64{fn: mul_11_uint64, fnname: "mul_11_uint64", in: 81, want: 891},
+ test_uint64{fn: mul_uint64_11, fnname: "mul_uint64_11", in: 81, want: 891},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 3, want: 39},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 3, want: 39},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 5, want: 65},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 5, want: 65},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 7, want: 91},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 7, want: 91},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 9, want: 117},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 9, want: 117},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 10, want: 130},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 10, want: 130},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 11, want: 143},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 11, want: 143},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 13, want: 169},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 13, want: 169},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 19, want: 247},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 19, want: 247},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 21, want: 273},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 21, want: 273},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 25, want: 325},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 25, want: 325},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 27, want: 351},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 27, want: 351},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 37, want: 481},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 37, want: 481},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 41, want: 533},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 41, want: 533},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 45, want: 585},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 45, want: 585},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 73, want: 949},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 73, want: 949},
+ test_uint64{fn: mul_13_uint64, fnname: "mul_13_uint64", in: 81, want: 1053},
+ test_uint64{fn: mul_uint64_13, fnname: "mul_uint64_13", in: 81, want: 1053},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 3, want: 57},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 3, want: 57},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 5, want: 95},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 5, want: 95},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 7, want: 133},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 7, want: 133},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 9, want: 171},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 9, want: 171},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 10, want: 190},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 10, want: 190},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 11, want: 209},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 11, want: 209},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 13, want: 247},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 13, want: 247},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 19, want: 361},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 19, want: 361},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 21, want: 399},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 21, want: 399},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 25, want: 475},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 25, want: 475},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 27, want: 513},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 27, want: 513},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 37, want: 703},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 37, want: 703},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 41, want: 779},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 41, want: 779},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 45, want: 855},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 45, want: 855},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 73, want: 1387},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 73, want: 1387},
+ test_uint64{fn: mul_19_uint64, fnname: "mul_19_uint64", in: 81, want: 1539},
+ test_uint64{fn: mul_uint64_19, fnname: "mul_uint64_19", in: 81, want: 1539},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 3, want: 63},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 3, want: 63},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 5, want: 105},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 5, want: 105},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 7, want: 147},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 7, want: 147},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 9, want: 189},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 9, want: 189},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 10, want: 210},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 10, want: 210},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 11, want: 231},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 11, want: 231},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 13, want: 273},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 13, want: 273},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 19, want: 399},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 19, want: 399},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 21, want: 441},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 21, want: 441},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 25, want: 525},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 25, want: 525},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 27, want: 567},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 27, want: 567},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 37, want: 777},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 37, want: 777},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 41, want: 861},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 41, want: 861},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 45, want: 945},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 45, want: 945},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 73, want: 1533},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 73, want: 1533},
+ test_uint64{fn: mul_21_uint64, fnname: "mul_21_uint64", in: 81, want: 1701},
+ test_uint64{fn: mul_uint64_21, fnname: "mul_uint64_21", in: 81, want: 1701},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 3, want: 75},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 3, want: 75},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 5, want: 125},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 5, want: 125},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 7, want: 175},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 7, want: 175},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 9, want: 225},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 9, want: 225},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 10, want: 250},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 10, want: 250},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 11, want: 275},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 11, want: 275},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 13, want: 325},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 13, want: 325},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 19, want: 475},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 19, want: 475},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 21, want: 525},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 21, want: 525},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 25, want: 625},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 25, want: 625},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 27, want: 675},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 27, want: 675},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 37, want: 925},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 37, want: 925},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 41, want: 1025},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 41, want: 1025},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 45, want: 1125},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 45, want: 1125},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 73, want: 1825},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 73, want: 1825},
+ test_uint64{fn: mul_25_uint64, fnname: "mul_25_uint64", in: 81, want: 2025},
+ test_uint64{fn: mul_uint64_25, fnname: "mul_uint64_25", in: 81, want: 2025},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 3, want: 81},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 3, want: 81},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 5, want: 135},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 5, want: 135},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 7, want: 189},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 7, want: 189},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 9, want: 243},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 9, want: 243},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 10, want: 270},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 10, want: 270},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 11, want: 297},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 11, want: 297},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 13, want: 351},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 13, want: 351},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 19, want: 513},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 19, want: 513},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 21, want: 567},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 21, want: 567},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 25, want: 675},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 25, want: 675},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 27, want: 729},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 27, want: 729},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 37, want: 999},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 37, want: 999},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 41, want: 1107},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 41, want: 1107},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 45, want: 1215},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 45, want: 1215},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 73, want: 1971},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 73, want: 1971},
+ test_uint64{fn: mul_27_uint64, fnname: "mul_27_uint64", in: 81, want: 2187},
+ test_uint64{fn: mul_uint64_27, fnname: "mul_uint64_27", in: 81, want: 2187},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 3, want: 111},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 3, want: 111},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 5, want: 185},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 5, want: 185},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 7, want: 259},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 7, want: 259},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 9, want: 333},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 9, want: 333},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 10, want: 370},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 10, want: 370},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 11, want: 407},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 11, want: 407},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 13, want: 481},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 13, want: 481},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 19, want: 703},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 19, want: 703},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 21, want: 777},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 21, want: 777},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 25, want: 925},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 25, want: 925},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 27, want: 999},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 27, want: 999},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 37, want: 1369},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 37, want: 1369},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 41, want: 1517},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 41, want: 1517},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 45, want: 1665},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 45, want: 1665},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 73, want: 2701},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 73, want: 2701},
+ test_uint64{fn: mul_37_uint64, fnname: "mul_37_uint64", in: 81, want: 2997},
+ test_uint64{fn: mul_uint64_37, fnname: "mul_uint64_37", in: 81, want: 2997},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 3, want: 123},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 3, want: 123},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 5, want: 205},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 5, want: 205},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 7, want: 287},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 7, want: 287},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 9, want: 369},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 9, want: 369},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 10, want: 410},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 10, want: 410},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 11, want: 451},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 11, want: 451},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 13, want: 533},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 13, want: 533},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 19, want: 779},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 19, want: 779},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 21, want: 861},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 21, want: 861},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 25, want: 1025},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 25, want: 1025},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 27, want: 1107},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 27, want: 1107},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 37, want: 1517},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 37, want: 1517},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 41, want: 1681},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 41, want: 1681},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 45, want: 1845},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 45, want: 1845},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 73, want: 2993},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 73, want: 2993},
+ test_uint64{fn: mul_41_uint64, fnname: "mul_41_uint64", in: 81, want: 3321},
+ test_uint64{fn: mul_uint64_41, fnname: "mul_uint64_41", in: 81, want: 3321},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 3, want: 135},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 3, want: 135},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 5, want: 225},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 5, want: 225},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 7, want: 315},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 7, want: 315},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 9, want: 405},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 9, want: 405},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 10, want: 450},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 10, want: 450},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 11, want: 495},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 11, want: 495},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 13, want: 585},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 13, want: 585},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 19, want: 855},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 19, want: 855},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 21, want: 945},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 21, want: 945},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 25, want: 1125},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 25, want: 1125},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 27, want: 1215},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 27, want: 1215},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 37, want: 1665},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 37, want: 1665},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 41, want: 1845},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 41, want: 1845},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 45, want: 2025},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 45, want: 2025},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 73, want: 3285},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 73, want: 3285},
+ test_uint64{fn: mul_45_uint64, fnname: "mul_45_uint64", in: 81, want: 3645},
+ test_uint64{fn: mul_uint64_45, fnname: "mul_uint64_45", in: 81, want: 3645},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 3, want: 219},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 3, want: 219},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 5, want: 365},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 5, want: 365},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 7, want: 511},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 7, want: 511},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 9, want: 657},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 9, want: 657},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 10, want: 730},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 10, want: 730},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 11, want: 803},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 11, want: 803},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 13, want: 949},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 13, want: 949},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 19, want: 1387},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 19, want: 1387},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 21, want: 1533},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 21, want: 1533},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 25, want: 1825},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 25, want: 1825},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 27, want: 1971},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 27, want: 1971},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 37, want: 2701},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 37, want: 2701},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 41, want: 2993},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 41, want: 2993},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 45, want: 3285},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 45, want: 3285},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 73, want: 5329},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 73, want: 5329},
+ test_uint64{fn: mul_73_uint64, fnname: "mul_73_uint64", in: 81, want: 5913},
+ test_uint64{fn: mul_uint64_73, fnname: "mul_uint64_73", in: 81, want: 5913},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 3, want: 243},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 3, want: 243},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 5, want: 405},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 5, want: 405},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 7, want: 567},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 7, want: 567},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 9, want: 729},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 9, want: 729},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 10, want: 810},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 10, want: 810},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 11, want: 891},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 11, want: 891},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 13, want: 1053},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 13, want: 1053},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 19, want: 1539},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 19, want: 1539},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 21, want: 1701},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 21, want: 1701},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 25, want: 2025},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 25, want: 2025},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 27, want: 2187},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 27, want: 2187},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 37, want: 2997},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 37, want: 2997},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 41, want: 3321},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 41, want: 3321},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 45, want: 3645},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 45, want: 3645},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 73, want: 5913},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 73, want: 5913},
+ test_uint64{fn: mul_81_uint64, fnname: "mul_81_uint64", in: 81, want: 6561},
+ test_uint64{fn: mul_uint64_81, fnname: "mul_uint64_81", in: 81, want: 6561}}
+
+type test_int64 struct {
+ fn func(int64) int64
+ fnname string
+ in int64
+ want int64
+}
+
+var tests_int64 = []test_int64{
+
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: -9223372036854775808, want: 0},
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: -9223372036854775807, want: 1},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: -9223372036854775807, want: 1},
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: -1, want: 9223372036854775807},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: -1, want: 9223372036854775807},
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: 0, want: -9223372036854775808},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: 0, want: -9223372036854775808},
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: 1, want: -9223372036854775807},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: 1, want: -9223372036854775807},
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: 4294967296, want: -9223372032559808512},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: 4294967296, want: -9223372032559808512},
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: 9223372036854775806, want: -2},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: 9223372036854775806, want: -2},
+ test_int64{fn: add_Neg9223372036854775808_int64, fnname: "add_Neg9223372036854775808_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: add_int64_Neg9223372036854775808, fnname: "add_int64_Neg9223372036854775808", in: 9223372036854775807, want: -1},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: -9223372036854775808, want: 1},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: -9223372036854775808, want: 1},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: -9223372036854775807, want: 2},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: -9223372036854775807, want: 2},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: -4294967296, want: 9223372032559808513},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: -4294967296, want: 9223372032559808513},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: -1, want: -9223372036854775808},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: -1, want: -9223372036854775808},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: 0, want: -9223372036854775807},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: 0, want: -9223372036854775807},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: 1, want: -9223372036854775806},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: 1, want: -9223372036854775806},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: 4294967296, want: -9223372032559808511},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: 4294967296, want: -9223372032559808511},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: 9223372036854775806, want: -1},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: 9223372036854775806, want: -1},
+ test_int64{fn: add_Neg9223372036854775807_int64, fnname: "add_Neg9223372036854775807_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: add_int64_Neg9223372036854775807, fnname: "add_int64_Neg9223372036854775807", in: 9223372036854775807, want: 0},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: -9223372036854775808, want: 9223372032559808512},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: -9223372036854775808, want: 9223372032559808512},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: -9223372036854775807, want: 9223372032559808513},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: -9223372036854775807, want: 9223372032559808513},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: -4294967296, want: -8589934592},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: -4294967296, want: -8589934592},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: -1, want: -4294967297},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: -1, want: -4294967297},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: 0, want: -4294967296},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: 0, want: -4294967296},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: 1, want: -4294967295},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: 1, want: -4294967295},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: 4294967296, want: 0},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: 4294967296, want: 0},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: 9223372036854775806, want: 9223372032559808510},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: 9223372036854775806, want: 9223372032559808510},
+ test_int64{fn: add_Neg4294967296_int64, fnname: "add_Neg4294967296_int64", in: 9223372036854775807, want: 9223372032559808511},
+ test_int64{fn: add_int64_Neg4294967296, fnname: "add_int64_Neg4294967296", in: 9223372036854775807, want: 9223372032559808511},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: -9223372036854775808, want: 9223372036854775807},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: -9223372036854775808, want: 9223372036854775807},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: -4294967296, want: -4294967297},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: -4294967296, want: -4294967297},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: -1, want: -2},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: -1, want: -2},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: 0, want: -1},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: 0, want: -1},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: 1, want: 0},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: 1, want: 0},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: 4294967296, want: 4294967295},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: 4294967296, want: 4294967295},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: 9223372036854775806, want: 9223372036854775805},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: 9223372036854775806, want: 9223372036854775805},
+ test_int64{fn: add_Neg1_int64, fnname: "add_Neg1_int64", in: 9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: add_int64_Neg1, fnname: "add_int64_Neg1", in: 9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: -4294967296, want: -4294967296},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: -1, want: -1},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: -1, want: -1},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: 0, want: 0},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: 0, want: 0},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: 1, want: 1},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: 1, want: 1},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: 4294967296, want: 4294967296},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: add_0_int64, fnname: "add_0_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: add_int64_0, fnname: "add_int64_0", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: -9223372036854775807, want: -9223372036854775806},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: -9223372036854775807, want: -9223372036854775806},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: -4294967296, want: -4294967295},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: -4294967296, want: -4294967295},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: -1, want: 0},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: -1, want: 0},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: 0, want: 1},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: 0, want: 1},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: 1, want: 2},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: 1, want: 2},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: 4294967296, want: 4294967297},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: 4294967296, want: 4294967297},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: add_1_int64, fnname: "add_1_int64", in: 9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: add_int64_1, fnname: "add_int64_1", in: 9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: -9223372036854775808, want: -9223372032559808512},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: -9223372036854775808, want: -9223372032559808512},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: -9223372036854775807, want: -9223372032559808511},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: -9223372036854775807, want: -9223372032559808511},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: -4294967296, want: 0},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: -4294967296, want: 0},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: -1, want: 4294967295},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: -1, want: 4294967295},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: 0, want: 4294967296},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: 0, want: 4294967296},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: 1, want: 4294967297},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: 1, want: 4294967297},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: 4294967296, want: 8589934592},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: 4294967296, want: 8589934592},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: 9223372036854775806, want: -9223372032559808514},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: 9223372036854775806, want: -9223372032559808514},
+ test_int64{fn: add_4294967296_int64, fnname: "add_4294967296_int64", in: 9223372036854775807, want: -9223372032559808513},
+ test_int64{fn: add_int64_4294967296, fnname: "add_int64_4294967296", in: 9223372036854775807, want: -9223372032559808513},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: -9223372036854775808, want: -2},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: -9223372036854775808, want: -2},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: -9223372036854775807, want: -1},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: -4294967296, want: 9223372032559808510},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: -4294967296, want: 9223372032559808510},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: -1, want: 9223372036854775805},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: -1, want: 9223372036854775805},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: 0, want: 9223372036854775806},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: 0, want: 9223372036854775806},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: 1, want: 9223372036854775807},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: 1, want: 9223372036854775807},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: 4294967296, want: -9223372032559808514},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: 4294967296, want: -9223372032559808514},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: 9223372036854775806, want: -4},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: 9223372036854775806, want: -4},
+ test_int64{fn: add_9223372036854775806_int64, fnname: "add_9223372036854775806_int64", in: 9223372036854775807, want: -3},
+ test_int64{fn: add_int64_9223372036854775806, fnname: "add_int64_9223372036854775806", in: 9223372036854775807, want: -3},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: -9223372036854775808, want: -1},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: -9223372036854775808, want: -1},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: -9223372036854775807, want: 0},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: -4294967296, want: 9223372032559808511},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: -4294967296, want: 9223372032559808511},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: -1, want: 9223372036854775806},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: -1, want: 9223372036854775806},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: 0, want: 9223372036854775807},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: 0, want: 9223372036854775807},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: 1, want: -9223372036854775808},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: 1, want: -9223372036854775808},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: 4294967296, want: -9223372032559808513},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: 4294967296, want: -9223372032559808513},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: 9223372036854775806, want: -3},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: 9223372036854775806, want: -3},
+ test_int64{fn: add_9223372036854775807_int64, fnname: "add_9223372036854775807_int64", in: 9223372036854775807, want: -2},
+ test_int64{fn: add_int64_9223372036854775807, fnname: "add_int64_9223372036854775807", in: 9223372036854775807, want: -2},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: -9223372036854775808, want: 0},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: -9223372036854775807, want: 1},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: -4294967296, want: -9223372032559808512},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: -1, want: -9223372036854775807},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: -1, want: 9223372036854775807},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: 0, want: -9223372036854775808},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: 0, want: -9223372036854775808},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: 1, want: 9223372036854775807},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: 1, want: -9223372036854775807},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: 4294967296, want: 9223372032559808512},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: 4294967296, want: -9223372032559808512},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: 9223372036854775806, want: 2},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: 9223372036854775806, want: -2},
+ test_int64{fn: sub_Neg9223372036854775808_int64, fnname: "sub_Neg9223372036854775808_int64", in: 9223372036854775807, want: 1},
+ test_int64{fn: sub_int64_Neg9223372036854775808, fnname: "sub_int64_Neg9223372036854775808", in: 9223372036854775807, want: -1},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: -9223372036854775808, want: 1},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: -9223372036854775808, want: -1},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: -9223372036854775807, want: 0},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: -4294967296, want: -9223372032559808511},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: -4294967296, want: 9223372032559808511},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: -1, want: -9223372036854775806},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: -1, want: 9223372036854775806},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: 0, want: -9223372036854775807},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: 0, want: 9223372036854775807},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: 1, want: -9223372036854775808},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: 1, want: -9223372036854775808},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: 4294967296, want: 9223372032559808513},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: 4294967296, want: -9223372032559808513},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: 9223372036854775806, want: 3},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: 9223372036854775806, want: -3},
+ test_int64{fn: sub_Neg9223372036854775807_int64, fnname: "sub_Neg9223372036854775807_int64", in: 9223372036854775807, want: 2},
+ test_int64{fn: sub_int64_Neg9223372036854775807, fnname: "sub_int64_Neg9223372036854775807", in: 9223372036854775807, want: -2},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: -9223372036854775808, want: 9223372032559808512},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: -9223372036854775808, want: -9223372032559808512},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: -9223372036854775807, want: 9223372032559808511},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: -9223372036854775807, want: -9223372032559808511},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: -4294967296, want: 0},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: -4294967296, want: 0},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: -1, want: -4294967295},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: -1, want: 4294967295},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: 0, want: -4294967296},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: 0, want: 4294967296},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: 1, want: -4294967297},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: 1, want: 4294967297},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: 4294967296, want: -8589934592},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: 4294967296, want: 8589934592},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: 9223372036854775806, want: 9223372032559808514},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: 9223372036854775806, want: -9223372032559808514},
+ test_int64{fn: sub_Neg4294967296_int64, fnname: "sub_Neg4294967296_int64", in: 9223372036854775807, want: 9223372032559808513},
+ test_int64{fn: sub_int64_Neg4294967296, fnname: "sub_int64_Neg4294967296", in: 9223372036854775807, want: -9223372032559808513},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: -9223372036854775808, want: 9223372036854775807},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: -9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: -9223372036854775807, want: -9223372036854775806},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: -4294967296, want: 4294967295},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: -4294967296, want: -4294967295},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: -1, want: 0},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: -1, want: 0},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: 0, want: -1},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: 0, want: 1},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: 1, want: -2},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: 1, want: 2},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: 4294967296, want: -4294967297},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: 4294967296, want: 4294967297},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: 9223372036854775806, want: -9223372036854775807},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: sub_Neg1_int64, fnname: "sub_Neg1_int64", in: 9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: sub_int64_Neg1, fnname: "sub_int64_Neg1", in: 9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: -9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: -4294967296, want: 4294967296},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: -4294967296, want: -4294967296},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: -1, want: 1},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: -1, want: -1},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: 0, want: 0},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: 0, want: 0},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: 1, want: -1},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: 1, want: 1},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: 4294967296, want: -4294967296},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: 4294967296, want: 4294967296},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: 9223372036854775806, want: -9223372036854775806},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: sub_0_int64, fnname: "sub_0_int64", in: 9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: sub_int64_0, fnname: "sub_int64_0", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: -9223372036854775808, want: 9223372036854775807},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: -4294967296, want: 4294967297},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: -4294967296, want: -4294967297},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: -1, want: 2},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: -1, want: -2},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: 0, want: 1},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: 0, want: -1},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: 1, want: 0},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: 1, want: 0},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: 4294967296, want: -4294967295},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: 4294967296, want: 4294967295},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: 9223372036854775806, want: -9223372036854775805},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: 9223372036854775806, want: 9223372036854775805},
+ test_int64{fn: sub_1_int64, fnname: "sub_1_int64", in: 9223372036854775807, want: -9223372036854775806},
+ test_int64{fn: sub_int64_1, fnname: "sub_int64_1", in: 9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: -9223372036854775808, want: -9223372032559808512},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: -9223372036854775808, want: 9223372032559808512},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: -9223372036854775807, want: -9223372032559808513},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: -9223372036854775807, want: 9223372032559808513},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: -4294967296, want: 8589934592},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: -4294967296, want: -8589934592},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: -1, want: 4294967297},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: -1, want: -4294967297},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: 0, want: 4294967296},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: 0, want: -4294967296},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: 1, want: 4294967295},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: 1, want: -4294967295},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: 4294967296, want: 0},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: 4294967296, want: 0},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: 9223372036854775806, want: -9223372032559808510},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: 9223372036854775806, want: 9223372032559808510},
+ test_int64{fn: sub_4294967296_int64, fnname: "sub_4294967296_int64", in: 9223372036854775807, want: -9223372032559808511},
+ test_int64{fn: sub_int64_4294967296, fnname: "sub_int64_4294967296", in: 9223372036854775807, want: 9223372032559808511},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: -9223372036854775808, want: -2},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: -9223372036854775808, want: 2},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: -9223372036854775807, want: -3},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: -9223372036854775807, want: 3},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: -4294967296, want: -9223372032559808514},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: -4294967296, want: 9223372032559808514},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: -1, want: 9223372036854775807},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: -1, want: -9223372036854775807},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: 0, want: 9223372036854775806},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: 0, want: -9223372036854775806},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: 1, want: 9223372036854775805},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: 1, want: -9223372036854775805},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: 4294967296, want: 9223372032559808510},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: 4294967296, want: -9223372032559808510},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: 9223372036854775806, want: 0},
+ test_int64{fn: sub_9223372036854775806_int64, fnname: "sub_9223372036854775806_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: sub_int64_9223372036854775806, fnname: "sub_int64_9223372036854775806", in: 9223372036854775807, want: 1},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: -9223372036854775808, want: -1},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: -9223372036854775808, want: 1},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: -9223372036854775807, want: -2},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: -9223372036854775807, want: 2},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: -4294967296, want: -9223372032559808513},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: -4294967296, want: 9223372032559808513},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: -1, want: -9223372036854775808},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: -1, want: -9223372036854775808},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: 0, want: 9223372036854775807},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: 0, want: -9223372036854775807},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: 1, want: 9223372036854775806},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: 1, want: -9223372036854775806},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: 4294967296, want: 9223372032559808511},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: 4294967296, want: -9223372032559808511},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: 9223372036854775806, want: 1},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: 9223372036854775806, want: -1},
+ test_int64{fn: sub_9223372036854775807_int64, fnname: "sub_9223372036854775807_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: sub_int64_9223372036854775807, fnname: "sub_int64_9223372036854775807", in: 9223372036854775807, want: 0},
+ test_int64{fn: div_Neg9223372036854775808_int64, fnname: "div_Neg9223372036854775808_int64", in: -9223372036854775808, want: 1},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: -9223372036854775808, want: 1},
+ test_int64{fn: div_Neg9223372036854775808_int64, fnname: "div_Neg9223372036854775808_int64", in: -9223372036854775807, want: 1},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: -9223372036854775807, want: 0},
+ test_int64{fn: div_Neg9223372036854775808_int64, fnname: "div_Neg9223372036854775808_int64", in: -4294967296, want: 2147483648},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: -4294967296, want: 0},
+ test_int64{fn: div_Neg9223372036854775808_int64, fnname: "div_Neg9223372036854775808_int64", in: -1, want: -9223372036854775808},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: -1, want: 0},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: 0, want: 0},
+ test_int64{fn: div_Neg9223372036854775808_int64, fnname: "div_Neg9223372036854775808_int64", in: 1, want: -9223372036854775808},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: 1, want: 0},
+ test_int64{fn: div_Neg9223372036854775808_int64, fnname: "div_Neg9223372036854775808_int64", in: 4294967296, want: -2147483648},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: 4294967296, want: 0},
+ test_int64{fn: div_Neg9223372036854775808_int64, fnname: "div_Neg9223372036854775808_int64", in: 9223372036854775806, want: -1},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: 9223372036854775806, want: 0},
+ test_int64{fn: div_Neg9223372036854775808_int64, fnname: "div_Neg9223372036854775808_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: div_int64_Neg9223372036854775808, fnname: "div_int64_Neg9223372036854775808", in: 9223372036854775807, want: 0},
+ test_int64{fn: div_Neg9223372036854775807_int64, fnname: "div_Neg9223372036854775807_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: -9223372036854775808, want: 1},
+ test_int64{fn: div_Neg9223372036854775807_int64, fnname: "div_Neg9223372036854775807_int64", in: -9223372036854775807, want: 1},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: -9223372036854775807, want: 1},
+ test_int64{fn: div_Neg9223372036854775807_int64, fnname: "div_Neg9223372036854775807_int64", in: -4294967296, want: 2147483647},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: -4294967296, want: 0},
+ test_int64{fn: div_Neg9223372036854775807_int64, fnname: "div_Neg9223372036854775807_int64", in: -1, want: 9223372036854775807},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: -1, want: 0},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: 0, want: 0},
+ test_int64{fn: div_Neg9223372036854775807_int64, fnname: "div_Neg9223372036854775807_int64", in: 1, want: -9223372036854775807},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: 1, want: 0},
+ test_int64{fn: div_Neg9223372036854775807_int64, fnname: "div_Neg9223372036854775807_int64", in: 4294967296, want: -2147483647},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: 4294967296, want: 0},
+ test_int64{fn: div_Neg9223372036854775807_int64, fnname: "div_Neg9223372036854775807_int64", in: 9223372036854775806, want: -1},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: 9223372036854775806, want: 0},
+ test_int64{fn: div_Neg9223372036854775807_int64, fnname: "div_Neg9223372036854775807_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: div_int64_Neg9223372036854775807, fnname: "div_int64_Neg9223372036854775807", in: 9223372036854775807, want: -1},
+ test_int64{fn: div_Neg4294967296_int64, fnname: "div_Neg4294967296_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: -9223372036854775808, want: 2147483648},
+ test_int64{fn: div_Neg4294967296_int64, fnname: "div_Neg4294967296_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: -9223372036854775807, want: 2147483647},
+ test_int64{fn: div_Neg4294967296_int64, fnname: "div_Neg4294967296_int64", in: -4294967296, want: 1},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: -4294967296, want: 1},
+ test_int64{fn: div_Neg4294967296_int64, fnname: "div_Neg4294967296_int64", in: -1, want: 4294967296},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: -1, want: 0},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: 0, want: 0},
+ test_int64{fn: div_Neg4294967296_int64, fnname: "div_Neg4294967296_int64", in: 1, want: -4294967296},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: 1, want: 0},
+ test_int64{fn: div_Neg4294967296_int64, fnname: "div_Neg4294967296_int64", in: 4294967296, want: -1},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: 4294967296, want: -1},
+ test_int64{fn: div_Neg4294967296_int64, fnname: "div_Neg4294967296_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: 9223372036854775806, want: -2147483647},
+ test_int64{fn: div_Neg4294967296_int64, fnname: "div_Neg4294967296_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: div_int64_Neg4294967296, fnname: "div_int64_Neg4294967296", in: 9223372036854775807, want: -2147483647},
+ test_int64{fn: div_Neg1_int64, fnname: "div_Neg1_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: div_Neg1_int64, fnname: "div_Neg1_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: -9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: div_Neg1_int64, fnname: "div_Neg1_int64", in: -4294967296, want: 0},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: -4294967296, want: 4294967296},
+ test_int64{fn: div_Neg1_int64, fnname: "div_Neg1_int64", in: -1, want: 1},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: -1, want: 1},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: 0, want: 0},
+ test_int64{fn: div_Neg1_int64, fnname: "div_Neg1_int64", in: 1, want: -1},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: 1, want: -1},
+ test_int64{fn: div_Neg1_int64, fnname: "div_Neg1_int64", in: 4294967296, want: 0},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: 4294967296, want: -4294967296},
+ test_int64{fn: div_Neg1_int64, fnname: "div_Neg1_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: 9223372036854775806, want: -9223372036854775806},
+ test_int64{fn: div_Neg1_int64, fnname: "div_Neg1_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: div_int64_Neg1, fnname: "div_int64_Neg1", in: 9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: div_0_int64, fnname: "div_0_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: div_0_int64, fnname: "div_0_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: div_0_int64, fnname: "div_0_int64", in: -4294967296, want: 0},
+ test_int64{fn: div_0_int64, fnname: "div_0_int64", in: -1, want: 0},
+ test_int64{fn: div_0_int64, fnname: "div_0_int64", in: 1, want: 0},
+ test_int64{fn: div_0_int64, fnname: "div_0_int64", in: 4294967296, want: 0},
+ test_int64{fn: div_0_int64, fnname: "div_0_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: div_0_int64, fnname: "div_0_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: div_1_int64, fnname: "div_1_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: div_1_int64, fnname: "div_1_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: div_1_int64, fnname: "div_1_int64", in: -4294967296, want: 0},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: -4294967296, want: -4294967296},
+ test_int64{fn: div_1_int64, fnname: "div_1_int64", in: -1, want: -1},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: -1, want: -1},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: 0, want: 0},
+ test_int64{fn: div_1_int64, fnname: "div_1_int64", in: 1, want: 1},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: 1, want: 1},
+ test_int64{fn: div_1_int64, fnname: "div_1_int64", in: 4294967296, want: 0},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: 4294967296, want: 4294967296},
+ test_int64{fn: div_1_int64, fnname: "div_1_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: div_1_int64, fnname: "div_1_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: div_int64_1, fnname: "div_int64_1", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: div_4294967296_int64, fnname: "div_4294967296_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: -9223372036854775808, want: -2147483648},
+ test_int64{fn: div_4294967296_int64, fnname: "div_4294967296_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: -9223372036854775807, want: -2147483647},
+ test_int64{fn: div_4294967296_int64, fnname: "div_4294967296_int64", in: -4294967296, want: -1},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: -4294967296, want: -1},
+ test_int64{fn: div_4294967296_int64, fnname: "div_4294967296_int64", in: -1, want: -4294967296},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: -1, want: 0},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: 0, want: 0},
+ test_int64{fn: div_4294967296_int64, fnname: "div_4294967296_int64", in: 1, want: 4294967296},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: 1, want: 0},
+ test_int64{fn: div_4294967296_int64, fnname: "div_4294967296_int64", in: 4294967296, want: 1},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: 4294967296, want: 1},
+ test_int64{fn: div_4294967296_int64, fnname: "div_4294967296_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: 9223372036854775806, want: 2147483647},
+ test_int64{fn: div_4294967296_int64, fnname: "div_4294967296_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: div_int64_4294967296, fnname: "div_int64_4294967296", in: 9223372036854775807, want: 2147483647},
+ test_int64{fn: div_9223372036854775806_int64, fnname: "div_9223372036854775806_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: -9223372036854775808, want: -1},
+ test_int64{fn: div_9223372036854775806_int64, fnname: "div_9223372036854775806_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: -9223372036854775807, want: -1},
+ test_int64{fn: div_9223372036854775806_int64, fnname: "div_9223372036854775806_int64", in: -4294967296, want: -2147483647},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: -4294967296, want: 0},
+ test_int64{fn: div_9223372036854775806_int64, fnname: "div_9223372036854775806_int64", in: -1, want: -9223372036854775806},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: -1, want: 0},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: 0, want: 0},
+ test_int64{fn: div_9223372036854775806_int64, fnname: "div_9223372036854775806_int64", in: 1, want: 9223372036854775806},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: 1, want: 0},
+ test_int64{fn: div_9223372036854775806_int64, fnname: "div_9223372036854775806_int64", in: 4294967296, want: 2147483647},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: 4294967296, want: 0},
+ test_int64{fn: div_9223372036854775806_int64, fnname: "div_9223372036854775806_int64", in: 9223372036854775806, want: 1},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: 9223372036854775806, want: 1},
+ test_int64{fn: div_9223372036854775806_int64, fnname: "div_9223372036854775806_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: div_int64_9223372036854775806, fnname: "div_int64_9223372036854775806", in: 9223372036854775807, want: 1},
+ test_int64{fn: div_9223372036854775807_int64, fnname: "div_9223372036854775807_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: -9223372036854775808, want: -1},
+ test_int64{fn: div_9223372036854775807_int64, fnname: "div_9223372036854775807_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: -9223372036854775807, want: -1},
+ test_int64{fn: div_9223372036854775807_int64, fnname: "div_9223372036854775807_int64", in: -4294967296, want: -2147483647},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: -4294967296, want: 0},
+ test_int64{fn: div_9223372036854775807_int64, fnname: "div_9223372036854775807_int64", in: -1, want: -9223372036854775807},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: -1, want: 0},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: 0, want: 0},
+ test_int64{fn: div_9223372036854775807_int64, fnname: "div_9223372036854775807_int64", in: 1, want: 9223372036854775807},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: 1, want: 0},
+ test_int64{fn: div_9223372036854775807_int64, fnname: "div_9223372036854775807_int64", in: 4294967296, want: 2147483647},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: 4294967296, want: 0},
+ test_int64{fn: div_9223372036854775807_int64, fnname: "div_9223372036854775807_int64", in: 9223372036854775806, want: 1},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: 9223372036854775806, want: 0},
+ test_int64{fn: div_9223372036854775807_int64, fnname: "div_9223372036854775807_int64", in: 9223372036854775807, want: 1},
+ test_int64{fn: div_int64_9223372036854775807, fnname: "div_int64_9223372036854775807", in: 9223372036854775807, want: 1},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: -4294967296, want: 0},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: -4294967296, want: 0},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: -1, want: -9223372036854775808},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: -1, want: -9223372036854775808},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: 0, want: 0},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: 1, want: -9223372036854775808},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: 1, want: -9223372036854775808},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: 4294967296, want: 0},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: 4294967296, want: 0},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: 9223372036854775806, want: 0},
+ test_int64{fn: mul_Neg9223372036854775808_int64, fnname: "mul_Neg9223372036854775808_int64", in: 9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: mul_int64_Neg9223372036854775808, fnname: "mul_int64_Neg9223372036854775808", in: 9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: -9223372036854775807, want: 1},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: -9223372036854775807, want: 1},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: -4294967296, want: -4294967296},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: -1, want: 9223372036854775807},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: -1, want: 9223372036854775807},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: 0, want: 0},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: 1, want: -9223372036854775807},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: 1, want: -9223372036854775807},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: 4294967296, want: 4294967296},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: mul_Neg9223372036854775807_int64, fnname: "mul_Neg9223372036854775807_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: mul_int64_Neg9223372036854775807, fnname: "mul_int64_Neg9223372036854775807", in: 9223372036854775807, want: -1},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: -9223372036854775807, want: -4294967296},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: -9223372036854775807, want: -4294967296},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: -4294967296, want: 0},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: -4294967296, want: 0},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: -1, want: 4294967296},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: -1, want: 4294967296},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: 0, want: 0},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: 1, want: -4294967296},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: 1, want: -4294967296},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: 4294967296, want: 0},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: 4294967296, want: 0},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: 9223372036854775806, want: 8589934592},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: 9223372036854775806, want: 8589934592},
+ test_int64{fn: mul_Neg4294967296_int64, fnname: "mul_Neg4294967296_int64", in: 9223372036854775807, want: 4294967296},
+ test_int64{fn: mul_int64_Neg4294967296, fnname: "mul_int64_Neg4294967296", in: 9223372036854775807, want: 4294967296},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: -9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: -9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: -4294967296, want: 4294967296},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: -4294967296, want: 4294967296},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: -1, want: 1},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: -1, want: 1},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: 0, want: 0},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: 1, want: -1},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: 1, want: -1},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: 4294967296, want: -4294967296},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: 4294967296, want: -4294967296},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: 9223372036854775806, want: -9223372036854775806},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: 9223372036854775806, want: -9223372036854775806},
+ test_int64{fn: mul_Neg1_int64, fnname: "mul_Neg1_int64", in: 9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: mul_int64_Neg1, fnname: "mul_int64_Neg1", in: 9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: -9223372036854775807, want: 0},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: -4294967296, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: -4294967296, want: 0},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: -1, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: -1, want: 0},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: 0, want: 0},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: 1, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: 1, want: 0},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: 4294967296, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: 4294967296, want: 0},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: 9223372036854775806, want: 0},
+ test_int64{fn: mul_0_int64, fnname: "mul_0_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: mul_int64_0, fnname: "mul_int64_0", in: 9223372036854775807, want: 0},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: -4294967296, want: -4294967296},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: -1, want: -1},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: -1, want: -1},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: 0, want: 0},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: 1, want: 1},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: 1, want: 1},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: 4294967296, want: 4294967296},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: mul_1_int64, fnname: "mul_1_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: mul_int64_1, fnname: "mul_int64_1", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: -9223372036854775807, want: 4294967296},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: -9223372036854775807, want: 4294967296},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: -4294967296, want: 0},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: -4294967296, want: 0},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: -1, want: -4294967296},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: -1, want: -4294967296},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: 0, want: 0},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: 1, want: 4294967296},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: 1, want: 4294967296},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: 4294967296, want: 0},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: 4294967296, want: 0},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: 9223372036854775806, want: -8589934592},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: 9223372036854775806, want: -8589934592},
+ test_int64{fn: mul_4294967296_int64, fnname: "mul_4294967296_int64", in: 9223372036854775807, want: -4294967296},
+ test_int64{fn: mul_int64_4294967296, fnname: "mul_int64_4294967296", in: 9223372036854775807, want: -4294967296},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: -9223372036854775808, want: 0},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: -9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: -9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: -4294967296, want: 8589934592},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: -4294967296, want: 8589934592},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: -1, want: -9223372036854775806},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: -1, want: -9223372036854775806},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: 0, want: 0},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: 1, want: 9223372036854775806},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: 1, want: 9223372036854775806},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: 4294967296, want: -8589934592},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: 4294967296, want: -8589934592},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: 9223372036854775806, want: 4},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: 9223372036854775806, want: 4},
+ test_int64{fn: mul_9223372036854775806_int64, fnname: "mul_9223372036854775806_int64", in: 9223372036854775807, want: -9223372036854775806},
+ test_int64{fn: mul_int64_9223372036854775806, fnname: "mul_int64_9223372036854775806", in: 9223372036854775807, want: -9223372036854775806},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: -9223372036854775807, want: -1},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: -4294967296, want: 4294967296},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: -4294967296, want: 4294967296},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: -1, want: -9223372036854775807},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: -1, want: -9223372036854775807},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: 0, want: 0},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: 0, want: 0},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: 1, want: 9223372036854775807},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: 1, want: 9223372036854775807},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: 4294967296, want: -4294967296},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: 4294967296, want: -4294967296},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: 9223372036854775806, want: -9223372036854775806},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: 9223372036854775806, want: -9223372036854775806},
+ test_int64{fn: mul_9223372036854775807_int64, fnname: "mul_9223372036854775807_int64", in: 9223372036854775807, want: 1},
+ test_int64{fn: mul_int64_9223372036854775807, fnname: "mul_int64_9223372036854775807", in: 9223372036854775807, want: 1},
+ test_int64{fn: mod_Neg9223372036854775808_int64, fnname: "mod_Neg9223372036854775808_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: -9223372036854775808, want: 0},
+ test_int64{fn: mod_Neg9223372036854775808_int64, fnname: "mod_Neg9223372036854775808_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: mod_Neg9223372036854775808_int64, fnname: "mod_Neg9223372036854775808_int64", in: -4294967296, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: -4294967296, want: -4294967296},
+ test_int64{fn: mod_Neg9223372036854775808_int64, fnname: "mod_Neg9223372036854775808_int64", in: -1, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: -1, want: -1},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: 0, want: 0},
+ test_int64{fn: mod_Neg9223372036854775808_int64, fnname: "mod_Neg9223372036854775808_int64", in: 1, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: 1, want: 1},
+ test_int64{fn: mod_Neg9223372036854775808_int64, fnname: "mod_Neg9223372036854775808_int64", in: 4294967296, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: 4294967296, want: 4294967296},
+ test_int64{fn: mod_Neg9223372036854775808_int64, fnname: "mod_Neg9223372036854775808_int64", in: 9223372036854775806, want: -2},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: mod_Neg9223372036854775808_int64, fnname: "mod_Neg9223372036854775808_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: mod_int64_Neg9223372036854775808, fnname: "mod_int64_Neg9223372036854775808", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: mod_Neg9223372036854775807_int64, fnname: "mod_Neg9223372036854775807_int64", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: -9223372036854775808, want: -1},
+ test_int64{fn: mod_Neg9223372036854775807_int64, fnname: "mod_Neg9223372036854775807_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: -9223372036854775807, want: 0},
+ test_int64{fn: mod_Neg9223372036854775807_int64, fnname: "mod_Neg9223372036854775807_int64", in: -4294967296, want: -4294967295},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: -4294967296, want: -4294967296},
+ test_int64{fn: mod_Neg9223372036854775807_int64, fnname: "mod_Neg9223372036854775807_int64", in: -1, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: -1, want: -1},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: 0, want: 0},
+ test_int64{fn: mod_Neg9223372036854775807_int64, fnname: "mod_Neg9223372036854775807_int64", in: 1, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: 1, want: 1},
+ test_int64{fn: mod_Neg9223372036854775807_int64, fnname: "mod_Neg9223372036854775807_int64", in: 4294967296, want: -4294967295},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: 4294967296, want: 4294967296},
+ test_int64{fn: mod_Neg9223372036854775807_int64, fnname: "mod_Neg9223372036854775807_int64", in: 9223372036854775806, want: -1},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: mod_Neg9223372036854775807_int64, fnname: "mod_Neg9223372036854775807_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: mod_int64_Neg9223372036854775807, fnname: "mod_int64_Neg9223372036854775807", in: 9223372036854775807, want: 0},
+ test_int64{fn: mod_Neg4294967296_int64, fnname: "mod_Neg4294967296_int64", in: -9223372036854775808, want: -4294967296},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: -9223372036854775808, want: 0},
+ test_int64{fn: mod_Neg4294967296_int64, fnname: "mod_Neg4294967296_int64", in: -9223372036854775807, want: -4294967296},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: -9223372036854775807, want: -4294967295},
+ test_int64{fn: mod_Neg4294967296_int64, fnname: "mod_Neg4294967296_int64", in: -4294967296, want: 0},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: -4294967296, want: 0},
+ test_int64{fn: mod_Neg4294967296_int64, fnname: "mod_Neg4294967296_int64", in: -1, want: 0},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: -1, want: -1},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: 0, want: 0},
+ test_int64{fn: mod_Neg4294967296_int64, fnname: "mod_Neg4294967296_int64", in: 1, want: 0},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: 1, want: 1},
+ test_int64{fn: mod_Neg4294967296_int64, fnname: "mod_Neg4294967296_int64", in: 4294967296, want: 0},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: 4294967296, want: 0},
+ test_int64{fn: mod_Neg4294967296_int64, fnname: "mod_Neg4294967296_int64", in: 9223372036854775806, want: -4294967296},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: 9223372036854775806, want: 4294967294},
+ test_int64{fn: mod_Neg4294967296_int64, fnname: "mod_Neg4294967296_int64", in: 9223372036854775807, want: -4294967296},
+ test_int64{fn: mod_int64_Neg4294967296, fnname: "mod_int64_Neg4294967296", in: 9223372036854775807, want: 4294967295},
+ test_int64{fn: mod_Neg1_int64, fnname: "mod_Neg1_int64", in: -9223372036854775808, want: -1},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: -9223372036854775808, want: 0},
+ test_int64{fn: mod_Neg1_int64, fnname: "mod_Neg1_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: -9223372036854775807, want: 0},
+ test_int64{fn: mod_Neg1_int64, fnname: "mod_Neg1_int64", in: -4294967296, want: -1},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: -4294967296, want: 0},
+ test_int64{fn: mod_Neg1_int64, fnname: "mod_Neg1_int64", in: -1, want: 0},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: -1, want: 0},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: 0, want: 0},
+ test_int64{fn: mod_Neg1_int64, fnname: "mod_Neg1_int64", in: 1, want: 0},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: 1, want: 0},
+ test_int64{fn: mod_Neg1_int64, fnname: "mod_Neg1_int64", in: 4294967296, want: -1},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: 4294967296, want: 0},
+ test_int64{fn: mod_Neg1_int64, fnname: "mod_Neg1_int64", in: 9223372036854775806, want: -1},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: 9223372036854775806, want: 0},
+ test_int64{fn: mod_Neg1_int64, fnname: "mod_Neg1_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: mod_int64_Neg1, fnname: "mod_int64_Neg1", in: 9223372036854775807, want: 0},
+ test_int64{fn: mod_0_int64, fnname: "mod_0_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: mod_0_int64, fnname: "mod_0_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: mod_0_int64, fnname: "mod_0_int64", in: -4294967296, want: 0},
+ test_int64{fn: mod_0_int64, fnname: "mod_0_int64", in: -1, want: 0},
+ test_int64{fn: mod_0_int64, fnname: "mod_0_int64", in: 1, want: 0},
+ test_int64{fn: mod_0_int64, fnname: "mod_0_int64", in: 4294967296, want: 0},
+ test_int64{fn: mod_0_int64, fnname: "mod_0_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: mod_0_int64, fnname: "mod_0_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: mod_1_int64, fnname: "mod_1_int64", in: -9223372036854775808, want: 1},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: -9223372036854775808, want: 0},
+ test_int64{fn: mod_1_int64, fnname: "mod_1_int64", in: -9223372036854775807, want: 1},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: -9223372036854775807, want: 0},
+ test_int64{fn: mod_1_int64, fnname: "mod_1_int64", in: -4294967296, want: 1},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: -4294967296, want: 0},
+ test_int64{fn: mod_1_int64, fnname: "mod_1_int64", in: -1, want: 0},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: -1, want: 0},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: 0, want: 0},
+ test_int64{fn: mod_1_int64, fnname: "mod_1_int64", in: 1, want: 0},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: 1, want: 0},
+ test_int64{fn: mod_1_int64, fnname: "mod_1_int64", in: 4294967296, want: 1},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: 4294967296, want: 0},
+ test_int64{fn: mod_1_int64, fnname: "mod_1_int64", in: 9223372036854775806, want: 1},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: 9223372036854775806, want: 0},
+ test_int64{fn: mod_1_int64, fnname: "mod_1_int64", in: 9223372036854775807, want: 1},
+ test_int64{fn: mod_int64_1, fnname: "mod_int64_1", in: 9223372036854775807, want: 0},
+ test_int64{fn: mod_4294967296_int64, fnname: "mod_4294967296_int64", in: -9223372036854775808, want: 4294967296},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: -9223372036854775808, want: 0},
+ test_int64{fn: mod_4294967296_int64, fnname: "mod_4294967296_int64", in: -9223372036854775807, want: 4294967296},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: -9223372036854775807, want: -4294967295},
+ test_int64{fn: mod_4294967296_int64, fnname: "mod_4294967296_int64", in: -4294967296, want: 0},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: -4294967296, want: 0},
+ test_int64{fn: mod_4294967296_int64, fnname: "mod_4294967296_int64", in: -1, want: 0},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: -1, want: -1},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: 0, want: 0},
+ test_int64{fn: mod_4294967296_int64, fnname: "mod_4294967296_int64", in: 1, want: 0},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: 1, want: 1},
+ test_int64{fn: mod_4294967296_int64, fnname: "mod_4294967296_int64", in: 4294967296, want: 0},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: 4294967296, want: 0},
+ test_int64{fn: mod_4294967296_int64, fnname: "mod_4294967296_int64", in: 9223372036854775806, want: 4294967296},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: 9223372036854775806, want: 4294967294},
+ test_int64{fn: mod_4294967296_int64, fnname: "mod_4294967296_int64", in: 9223372036854775807, want: 4294967296},
+ test_int64{fn: mod_int64_4294967296, fnname: "mod_int64_4294967296", in: 9223372036854775807, want: 4294967295},
+ test_int64{fn: mod_9223372036854775806_int64, fnname: "mod_9223372036854775806_int64", in: -9223372036854775808, want: 9223372036854775806},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: -9223372036854775808, want: -2},
+ test_int64{fn: mod_9223372036854775806_int64, fnname: "mod_9223372036854775806_int64", in: -9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: -9223372036854775807, want: -1},
+ test_int64{fn: mod_9223372036854775806_int64, fnname: "mod_9223372036854775806_int64", in: -4294967296, want: 4294967294},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: -4294967296, want: -4294967296},
+ test_int64{fn: mod_9223372036854775806_int64, fnname: "mod_9223372036854775806_int64", in: -1, want: 0},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: -1, want: -1},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: 0, want: 0},
+ test_int64{fn: mod_9223372036854775806_int64, fnname: "mod_9223372036854775806_int64", in: 1, want: 0},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: 1, want: 1},
+ test_int64{fn: mod_9223372036854775806_int64, fnname: "mod_9223372036854775806_int64", in: 4294967296, want: 4294967294},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: 4294967296, want: 4294967296},
+ test_int64{fn: mod_9223372036854775806_int64, fnname: "mod_9223372036854775806_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: 9223372036854775806, want: 0},
+ test_int64{fn: mod_9223372036854775806_int64, fnname: "mod_9223372036854775806_int64", in: 9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: mod_int64_9223372036854775806, fnname: "mod_int64_9223372036854775806", in: 9223372036854775807, want: 1},
+ test_int64{fn: mod_9223372036854775807_int64, fnname: "mod_9223372036854775807_int64", in: -9223372036854775808, want: 9223372036854775807},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: -9223372036854775808, want: -1},
+ test_int64{fn: mod_9223372036854775807_int64, fnname: "mod_9223372036854775807_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: -9223372036854775807, want: 0},
+ test_int64{fn: mod_9223372036854775807_int64, fnname: "mod_9223372036854775807_int64", in: -4294967296, want: 4294967295},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: -4294967296, want: -4294967296},
+ test_int64{fn: mod_9223372036854775807_int64, fnname: "mod_9223372036854775807_int64", in: -1, want: 0},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: -1, want: -1},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: 0, want: 0},
+ test_int64{fn: mod_9223372036854775807_int64, fnname: "mod_9223372036854775807_int64", in: 1, want: 0},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: 1, want: 1},
+ test_int64{fn: mod_9223372036854775807_int64, fnname: "mod_9223372036854775807_int64", in: 4294967296, want: 4294967295},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: 4294967296, want: 4294967296},
+ test_int64{fn: mod_9223372036854775807_int64, fnname: "mod_9223372036854775807_int64", in: 9223372036854775806, want: 1},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: mod_9223372036854775807_int64, fnname: "mod_9223372036854775807_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: mod_int64_9223372036854775807, fnname: "mod_int64_9223372036854775807", in: 9223372036854775807, want: 0},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: -4294967296, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: -4294967296, want: -9223372036854775808},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: -1, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: -1, want: -9223372036854775808},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: 0, want: 0},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: 1, want: 0},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: 1, want: 0},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: 4294967296, want: 0},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: 4294967296, want: 0},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: 9223372036854775806, want: 0},
+ test_int64{fn: and_Neg9223372036854775808_int64, fnname: "and_Neg9223372036854775808_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: and_int64_Neg9223372036854775808, fnname: "and_int64_Neg9223372036854775808", in: 9223372036854775807, want: 0},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: -4294967296, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: -4294967296, want: -9223372036854775808},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: -1, want: -9223372036854775807},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: -1, want: -9223372036854775807},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: 0, want: 0},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: 1, want: 1},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: 1, want: 1},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: 4294967296, want: 0},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: 4294967296, want: 0},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: 9223372036854775806, want: 0},
+ test_int64{fn: and_Neg9223372036854775807_int64, fnname: "and_Neg9223372036854775807_int64", in: 9223372036854775807, want: 1},
+ test_int64{fn: and_int64_Neg9223372036854775807, fnname: "and_int64_Neg9223372036854775807", in: 9223372036854775807, want: 1},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: -4294967296, want: -4294967296},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: -1, want: -4294967296},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: -1, want: -4294967296},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: 0, want: 0},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: 1, want: 0},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: 1, want: 0},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: 9223372036854775806, want: 9223372032559808512},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: 9223372036854775806, want: 9223372032559808512},
+ test_int64{fn: and_Neg4294967296_int64, fnname: "and_Neg4294967296_int64", in: 9223372036854775807, want: 9223372032559808512},
+ test_int64{fn: and_int64_Neg4294967296, fnname: "and_int64_Neg4294967296", in: 9223372036854775807, want: 9223372032559808512},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: -4294967296, want: -4294967296},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: -1, want: -1},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: -1, want: -1},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: 0, want: 0},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: 1, want: 1},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: 1, want: 1},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: and_Neg1_int64, fnname: "and_Neg1_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: and_int64_Neg1, fnname: "and_int64_Neg1", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: -9223372036854775807, want: 0},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: -4294967296, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: -4294967296, want: 0},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: -1, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: -1, want: 0},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: 0, want: 0},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: 1, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: 1, want: 0},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: 4294967296, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: 4294967296, want: 0},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: 9223372036854775806, want: 0},
+ test_int64{fn: and_0_int64, fnname: "and_0_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: and_int64_0, fnname: "and_int64_0", in: 9223372036854775807, want: 0},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: -9223372036854775807, want: 1},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: -9223372036854775807, want: 1},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: -4294967296, want: 0},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: -4294967296, want: 0},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: -1, want: 1},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: -1, want: 1},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: 0, want: 0},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: 1, want: 1},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: 1, want: 1},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: 4294967296, want: 0},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: 4294967296, want: 0},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: 9223372036854775806, want: 0},
+ test_int64{fn: and_1_int64, fnname: "and_1_int64", in: 9223372036854775807, want: 1},
+ test_int64{fn: and_int64_1, fnname: "and_int64_1", in: 9223372036854775807, want: 1},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: -9223372036854775807, want: 0},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: -4294967296, want: 4294967296},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: -4294967296, want: 4294967296},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: -1, want: 4294967296},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: -1, want: 4294967296},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: 0, want: 0},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: 1, want: 0},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: 1, want: 0},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: 9223372036854775806, want: 4294967296},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: 9223372036854775806, want: 4294967296},
+ test_int64{fn: and_4294967296_int64, fnname: "and_4294967296_int64", in: 9223372036854775807, want: 4294967296},
+ test_int64{fn: and_int64_4294967296, fnname: "and_int64_4294967296", in: 9223372036854775807, want: 4294967296},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: -9223372036854775807, want: 0},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: -1, want: 9223372036854775806},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: -1, want: 9223372036854775806},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: 0, want: 0},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: 1, want: 0},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: 1, want: 0},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: and_9223372036854775806_int64, fnname: "and_9223372036854775806_int64", in: 9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: and_int64_9223372036854775806, fnname: "and_int64_9223372036854775806", in: 9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: -9223372036854775808, want: 0},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: -9223372036854775807, want: 1},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: -9223372036854775807, want: 1},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: -1, want: 9223372036854775807},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: -1, want: 9223372036854775807},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: 0, want: 0},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: 0, want: 0},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: 1, want: 1},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: 1, want: 1},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: 4294967296, want: 4294967296},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: and_9223372036854775807_int64, fnname: "and_9223372036854775807_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: and_int64_9223372036854775807, fnname: "and_int64_9223372036854775807", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: -4294967296, want: -4294967296},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: -1, want: -1},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: 0, want: -9223372036854775808},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: 0, want: -9223372036854775808},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: 1, want: -9223372036854775807},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: 1, want: -9223372036854775807},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: 4294967296, want: -9223372032559808512},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: 4294967296, want: -9223372032559808512},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: 9223372036854775806, want: -2},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: 9223372036854775806, want: -2},
+ test_int64{fn: or_Neg9223372036854775808_int64, fnname: "or_Neg9223372036854775808_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: or_int64_Neg9223372036854775808, fnname: "or_int64_Neg9223372036854775808", in: 9223372036854775807, want: -1},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: -4294967296, want: -4294967295},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: -4294967296, want: -4294967295},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: -1, want: -1},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: 0, want: -9223372036854775807},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: 0, want: -9223372036854775807},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: 1, want: -9223372036854775807},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: 1, want: -9223372036854775807},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: 4294967296, want: -9223372032559808511},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: 4294967296, want: -9223372032559808511},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: 9223372036854775806, want: -1},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: 9223372036854775806, want: -1},
+ test_int64{fn: or_Neg9223372036854775807_int64, fnname: "or_Neg9223372036854775807_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: or_int64_Neg9223372036854775807, fnname: "or_int64_Neg9223372036854775807", in: 9223372036854775807, want: -1},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: -9223372036854775808, want: -4294967296},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: -9223372036854775808, want: -4294967296},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: -9223372036854775807, want: -4294967295},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: -9223372036854775807, want: -4294967295},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: -4294967296, want: -4294967296},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: -1, want: -1},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: 0, want: -4294967296},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: 0, want: -4294967296},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: 1, want: -4294967295},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: 1, want: -4294967295},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: 4294967296, want: -4294967296},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: 4294967296, want: -4294967296},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: 9223372036854775806, want: -2},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: 9223372036854775806, want: -2},
+ test_int64{fn: or_Neg4294967296_int64, fnname: "or_Neg4294967296_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: or_int64_Neg4294967296, fnname: "or_int64_Neg4294967296", in: 9223372036854775807, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: -9223372036854775808, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: -9223372036854775808, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: -9223372036854775807, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: -4294967296, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: -4294967296, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: -1, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: 0, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: 0, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: 1, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: 1, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: 4294967296, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: 4294967296, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: 9223372036854775806, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: 9223372036854775806, want: -1},
+ test_int64{fn: or_Neg1_int64, fnname: "or_Neg1_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: or_int64_Neg1, fnname: "or_int64_Neg1", in: 9223372036854775807, want: -1},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: -4294967296, want: -4294967296},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: -1, want: -1},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: 0, want: 0},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: 0, want: 0},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: 1, want: 1},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: 1, want: 1},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: 4294967296, want: 4294967296},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: or_0_int64, fnname: "or_0_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_int64_0, fnname: "or_int64_0", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: -4294967296, want: -4294967295},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: -4294967296, want: -4294967295},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: -1, want: -1},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: 0, want: 1},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: 0, want: 1},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: 1, want: 1},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: 1, want: 1},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: 4294967296, want: 4294967297},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: 4294967296, want: 4294967297},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: or_1_int64, fnname: "or_1_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_int64_1, fnname: "or_int64_1", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: -9223372036854775808, want: -9223372032559808512},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: -9223372036854775808, want: -9223372032559808512},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: -9223372036854775807, want: -9223372032559808511},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: -9223372036854775807, want: -9223372032559808511},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: -4294967296, want: -4294967296},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: -1, want: -1},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: 0, want: 4294967296},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: 0, want: 4294967296},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: 1, want: 4294967297},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: 1, want: 4294967297},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: 4294967296, want: 4294967296},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: or_4294967296_int64, fnname: "or_4294967296_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_int64_4294967296, fnname: "or_int64_4294967296", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: -9223372036854775808, want: -2},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: -9223372036854775808, want: -2},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: -9223372036854775807, want: -1},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: -4294967296, want: -2},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: -4294967296, want: -2},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: -1, want: -1},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: 0, want: 9223372036854775806},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: 0, want: 9223372036854775806},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: 1, want: 9223372036854775807},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: 1, want: 9223372036854775807},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: 4294967296, want: 9223372036854775806},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: 4294967296, want: 9223372036854775806},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: or_9223372036854775806_int64, fnname: "or_9223372036854775806_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_int64_9223372036854775806, fnname: "or_int64_9223372036854775806", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: -9223372036854775808, want: -1},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: -9223372036854775808, want: -1},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: -9223372036854775807, want: -1},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: -4294967296, want: -1},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: -4294967296, want: -1},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: -1, want: -1},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: -1, want: -1},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: 0, want: 9223372036854775807},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: 0, want: 9223372036854775807},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: 1, want: 9223372036854775807},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: 1, want: 9223372036854775807},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: 4294967296, want: 9223372036854775807},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: 4294967296, want: 9223372036854775807},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: or_9223372036854775807_int64, fnname: "or_9223372036854775807_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: or_int64_9223372036854775807, fnname: "or_int64_9223372036854775807", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: -9223372036854775808, want: 0},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: -9223372036854775808, want: 0},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: -9223372036854775807, want: 1},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: -9223372036854775807, want: 1},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: -4294967296, want: 9223372032559808512},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: -1, want: 9223372036854775807},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: -1, want: 9223372036854775807},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: 0, want: -9223372036854775808},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: 0, want: -9223372036854775808},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: 1, want: -9223372036854775807},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: 1, want: -9223372036854775807},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: 4294967296, want: -9223372032559808512},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: 4294967296, want: -9223372032559808512},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: 9223372036854775806, want: -2},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: 9223372036854775806, want: -2},
+ test_int64{fn: xor_Neg9223372036854775808_int64, fnname: "xor_Neg9223372036854775808_int64", in: 9223372036854775807, want: -1},
+ test_int64{fn: xor_int64_Neg9223372036854775808, fnname: "xor_int64_Neg9223372036854775808", in: 9223372036854775807, want: -1},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: -9223372036854775808, want: 1},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: -9223372036854775808, want: 1},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: -9223372036854775807, want: 0},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: -9223372036854775807, want: 0},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: -4294967296, want: 9223372032559808513},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: -4294967296, want: 9223372032559808513},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: -1, want: 9223372036854775806},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: -1, want: 9223372036854775806},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: 0, want: -9223372036854775807},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: 0, want: -9223372036854775807},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: 1, want: -9223372036854775808},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: 1, want: -9223372036854775808},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: 4294967296, want: -9223372032559808511},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: 4294967296, want: -9223372032559808511},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: 9223372036854775806, want: -1},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: 9223372036854775806, want: -1},
+ test_int64{fn: xor_Neg9223372036854775807_int64, fnname: "xor_Neg9223372036854775807_int64", in: 9223372036854775807, want: -2},
+ test_int64{fn: xor_int64_Neg9223372036854775807, fnname: "xor_int64_Neg9223372036854775807", in: 9223372036854775807, want: -2},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: -9223372036854775808, want: 9223372032559808512},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: -9223372036854775808, want: 9223372032559808512},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: -9223372036854775807, want: 9223372032559808513},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: -9223372036854775807, want: 9223372032559808513},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: -4294967296, want: 0},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: -4294967296, want: 0},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: -1, want: 4294967295},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: -1, want: 4294967295},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: 0, want: -4294967296},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: 0, want: -4294967296},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: 1, want: -4294967295},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: 1, want: -4294967295},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: 4294967296, want: -8589934592},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: 4294967296, want: -8589934592},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: 9223372036854775806, want: -9223372032559808514},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: 9223372036854775806, want: -9223372032559808514},
+ test_int64{fn: xor_Neg4294967296_int64, fnname: "xor_Neg4294967296_int64", in: 9223372036854775807, want: -9223372032559808513},
+ test_int64{fn: xor_int64_Neg4294967296, fnname: "xor_int64_Neg4294967296", in: 9223372036854775807, want: -9223372032559808513},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: -9223372036854775808, want: 9223372036854775807},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: -9223372036854775808, want: 9223372036854775807},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: -9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: -9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: -4294967296, want: 4294967295},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: -4294967296, want: 4294967295},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: -1, want: 0},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: -1, want: 0},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: 0, want: -1},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: 0, want: -1},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: 1, want: -2},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: 1, want: -2},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: 4294967296, want: -4294967297},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: 4294967296, want: -4294967297},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: 9223372036854775806, want: -9223372036854775807},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: 9223372036854775806, want: -9223372036854775807},
+ test_int64{fn: xor_Neg1_int64, fnname: "xor_Neg1_int64", in: 9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: xor_int64_Neg1, fnname: "xor_int64_Neg1", in: 9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: -9223372036854775808, want: -9223372036854775808},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: -9223372036854775807, want: -9223372036854775807},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: -4294967296, want: -4294967296},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: -4294967296, want: -4294967296},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: -1, want: -1},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: -1, want: -1},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: 0, want: 0},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: 0, want: 0},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: 1, want: 1},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: 1, want: 1},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: 4294967296, want: 4294967296},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: 4294967296, want: 4294967296},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: 9223372036854775806, want: 9223372036854775806},
+ test_int64{fn: xor_0_int64, fnname: "xor_0_int64", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: xor_int64_0, fnname: "xor_int64_0", in: 9223372036854775807, want: 9223372036854775807},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: -9223372036854775808, want: -9223372036854775807},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: -9223372036854775807, want: -9223372036854775808},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: -4294967296, want: -4294967295},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: -4294967296, want: -4294967295},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: -1, want: -2},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: -1, want: -2},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: 0, want: 1},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: 0, want: 1},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: 1, want: 0},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: 1, want: 0},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: 4294967296, want: 4294967297},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: 4294967296, want: 4294967297},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: 9223372036854775806, want: 9223372036854775807},
+ test_int64{fn: xor_1_int64, fnname: "xor_1_int64", in: 9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: xor_int64_1, fnname: "xor_int64_1", in: 9223372036854775807, want: 9223372036854775806},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: -9223372036854775808, want: -9223372032559808512},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: -9223372036854775808, want: -9223372032559808512},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: -9223372036854775807, want: -9223372032559808511},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: -9223372036854775807, want: -9223372032559808511},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: -4294967296, want: -8589934592},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: -4294967296, want: -8589934592},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: -1, want: -4294967297},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: -1, want: -4294967297},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: 0, want: 4294967296},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: 0, want: 4294967296},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: 1, want: 4294967297},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: 1, want: 4294967297},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: 4294967296, want: 0},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: 4294967296, want: 0},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: 9223372036854775806, want: 9223372032559808510},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: 9223372036854775806, want: 9223372032559808510},
+ test_int64{fn: xor_4294967296_int64, fnname: "xor_4294967296_int64", in: 9223372036854775807, want: 9223372032559808511},
+ test_int64{fn: xor_int64_4294967296, fnname: "xor_int64_4294967296", in: 9223372036854775807, want: 9223372032559808511},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: -9223372036854775808, want: -2},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: -9223372036854775808, want: -2},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: -9223372036854775807, want: -1},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: -9223372036854775807, want: -1},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: -4294967296, want: -9223372032559808514},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: -4294967296, want: -9223372032559808514},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: -1, want: -9223372036854775807},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: -1, want: -9223372036854775807},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: 0, want: 9223372036854775806},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: 0, want: 9223372036854775806},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: 1, want: 9223372036854775807},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: 1, want: 9223372036854775807},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: 4294967296, want: 9223372032559808510},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: 4294967296, want: 9223372032559808510},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: 9223372036854775806, want: 0},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: 9223372036854775806, want: 0},
+ test_int64{fn: xor_9223372036854775806_int64, fnname: "xor_9223372036854775806_int64", in: 9223372036854775807, want: 1},
+ test_int64{fn: xor_int64_9223372036854775806, fnname: "xor_int64_9223372036854775806", in: 9223372036854775807, want: 1},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: -9223372036854775808, want: -1},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: -9223372036854775808, want: -1},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: -9223372036854775807, want: -2},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: -9223372036854775807, want: -2},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: -4294967296, want: -9223372032559808513},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: -4294967296, want: -9223372032559808513},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: -1, want: -9223372036854775808},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: -1, want: -9223372036854775808},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: 0, want: 9223372036854775807},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: 0, want: 9223372036854775807},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: 1, want: 9223372036854775806},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: 1, want: 9223372036854775806},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: 4294967296, want: 9223372032559808511},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: 4294967296, want: 9223372032559808511},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: 9223372036854775806, want: 1},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: 9223372036854775806, want: 1},
+ test_int64{fn: xor_9223372036854775807_int64, fnname: "xor_9223372036854775807_int64", in: 9223372036854775807, want: 0},
+ test_int64{fn: xor_int64_9223372036854775807, fnname: "xor_int64_9223372036854775807", in: 9223372036854775807, want: 0}}
+
+type test_int64mul struct {
+ fn func(int64) int64
+ fnname string
+ in int64
+ want int64
+}
+
+var tests_int64mul = []test_int64{
+
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: -9, want: 81},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: -9, want: 81},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: -5, want: 45},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: -5, want: 45},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: -3, want: 27},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: -3, want: 27},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 3, want: -27},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 3, want: -27},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 5, want: -45},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 5, want: -45},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 7, want: -63},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 7, want: -63},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 9, want: -81},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 9, want: -81},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 10, want: -90},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 10, want: -90},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 11, want: -99},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 11, want: -99},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 13, want: -117},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 13, want: -117},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 19, want: -171},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 19, want: -171},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 21, want: -189},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 21, want: -189},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 25, want: -225},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 25, want: -225},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 27, want: -243},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 27, want: -243},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 37, want: -333},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 37, want: -333},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 41, want: -369},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 41, want: -369},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 45, want: -405},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 45, want: -405},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 73, want: -657},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 73, want: -657},
+ test_int64{fn: mul_Neg9_int64, fnname: "mul_Neg9_int64", in: 81, want: -729},
+ test_int64{fn: mul_int64_Neg9, fnname: "mul_int64_Neg9", in: 81, want: -729},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: -9, want: 45},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: -9, want: 45},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: -5, want: 25},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: -5, want: 25},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: -3, want: 15},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: -3, want: 15},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 3, want: -15},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 3, want: -15},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 5, want: -25},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 5, want: -25},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 7, want: -35},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 7, want: -35},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 9, want: -45},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 9, want: -45},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 10, want: -50},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 10, want: -50},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 11, want: -55},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 11, want: -55},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 13, want: -65},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 13, want: -65},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 19, want: -95},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 19, want: -95},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 21, want: -105},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 21, want: -105},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 25, want: -125},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 25, want: -125},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 27, want: -135},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 27, want: -135},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 37, want: -185},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 37, want: -185},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 41, want: -205},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 41, want: -205},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 45, want: -225},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 45, want: -225},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 73, want: -365},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 73, want: -365},
+ test_int64{fn: mul_Neg5_int64, fnname: "mul_Neg5_int64", in: 81, want: -405},
+ test_int64{fn: mul_int64_Neg5, fnname: "mul_int64_Neg5", in: 81, want: -405},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: -9, want: 27},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: -9, want: 27},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: -5, want: 15},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: -5, want: 15},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: -3, want: 9},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: -3, want: 9},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 3, want: -9},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 3, want: -9},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 5, want: -15},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 5, want: -15},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 7, want: -21},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 7, want: -21},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 9, want: -27},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 9, want: -27},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 10, want: -30},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 10, want: -30},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 11, want: -33},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 11, want: -33},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 13, want: -39},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 13, want: -39},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 19, want: -57},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 19, want: -57},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 21, want: -63},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 21, want: -63},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 25, want: -75},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 25, want: -75},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 27, want: -81},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 27, want: -81},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 37, want: -111},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 37, want: -111},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 41, want: -123},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 41, want: -123},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 45, want: -135},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 45, want: -135},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 73, want: -219},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 73, want: -219},
+ test_int64{fn: mul_Neg3_int64, fnname: "mul_Neg3_int64", in: 81, want: -243},
+ test_int64{fn: mul_int64_Neg3, fnname: "mul_int64_Neg3", in: 81, want: -243},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: -9, want: -27},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: -9, want: -27},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: -5, want: -15},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: -5, want: -15},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: -3, want: -9},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: -3, want: -9},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 3, want: 9},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 3, want: 9},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 5, want: 15},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 5, want: 15},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 7, want: 21},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 7, want: 21},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 9, want: 27},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 9, want: 27},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 10, want: 30},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 10, want: 30},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 11, want: 33},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 11, want: 33},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 13, want: 39},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 13, want: 39},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 19, want: 57},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 19, want: 57},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 21, want: 63},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 21, want: 63},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 25, want: 75},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 25, want: 75},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 27, want: 81},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 27, want: 81},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 37, want: 111},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 37, want: 111},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 41, want: 123},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 41, want: 123},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 45, want: 135},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 45, want: 135},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 73, want: 219},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 73, want: 219},
+ test_int64{fn: mul_3_int64, fnname: "mul_3_int64", in: 81, want: 243},
+ test_int64{fn: mul_int64_3, fnname: "mul_int64_3", in: 81, want: 243},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: -9, want: -45},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: -9, want: -45},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: -5, want: -25},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: -5, want: -25},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: -3, want: -15},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: -3, want: -15},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 3, want: 15},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 3, want: 15},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 5, want: 25},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 5, want: 25},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 7, want: 35},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 7, want: 35},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 9, want: 45},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 9, want: 45},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 10, want: 50},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 10, want: 50},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 11, want: 55},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 11, want: 55},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 13, want: 65},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 13, want: 65},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 19, want: 95},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 19, want: 95},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 21, want: 105},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 21, want: 105},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 25, want: 125},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 25, want: 125},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 27, want: 135},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 27, want: 135},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 37, want: 185},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 37, want: 185},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 41, want: 205},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 41, want: 205},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 45, want: 225},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 45, want: 225},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 73, want: 365},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 73, want: 365},
+ test_int64{fn: mul_5_int64, fnname: "mul_5_int64", in: 81, want: 405},
+ test_int64{fn: mul_int64_5, fnname: "mul_int64_5", in: 81, want: 405},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: -9, want: -63},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: -9, want: -63},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: -5, want: -35},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: -5, want: -35},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: -3, want: -21},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: -3, want: -21},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 3, want: 21},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 3, want: 21},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 5, want: 35},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 5, want: 35},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 7, want: 49},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 7, want: 49},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 9, want: 63},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 9, want: 63},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 10, want: 70},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 10, want: 70},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 11, want: 77},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 11, want: 77},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 13, want: 91},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 13, want: 91},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 19, want: 133},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 19, want: 133},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 21, want: 147},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 21, want: 147},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 25, want: 175},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 25, want: 175},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 27, want: 189},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 27, want: 189},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 37, want: 259},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 37, want: 259},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 41, want: 287},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 41, want: 287},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 45, want: 315},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 45, want: 315},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 73, want: 511},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 73, want: 511},
+ test_int64{fn: mul_7_int64, fnname: "mul_7_int64", in: 81, want: 567},
+ test_int64{fn: mul_int64_7, fnname: "mul_int64_7", in: 81, want: 567},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: -9, want: -81},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: -9, want: -81},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: -5, want: -45},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: -5, want: -45},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: -3, want: -27},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: -3, want: -27},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 3, want: 27},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 3, want: 27},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 5, want: 45},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 5, want: 45},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 7, want: 63},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 7, want: 63},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 9, want: 81},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 9, want: 81},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 10, want: 90},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 10, want: 90},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 11, want: 99},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 11, want: 99},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 13, want: 117},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 13, want: 117},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 19, want: 171},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 19, want: 171},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 21, want: 189},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 21, want: 189},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 25, want: 225},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 25, want: 225},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 27, want: 243},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 27, want: 243},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 37, want: 333},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 37, want: 333},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 41, want: 369},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 41, want: 369},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 45, want: 405},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 45, want: 405},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 73, want: 657},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 73, want: 657},
+ test_int64{fn: mul_9_int64, fnname: "mul_9_int64", in: 81, want: 729},
+ test_int64{fn: mul_int64_9, fnname: "mul_int64_9", in: 81, want: 729},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: -9, want: -90},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: -9, want: -90},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: -5, want: -50},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: -5, want: -50},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: -3, want: -30},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: -3, want: -30},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 3, want: 30},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 3, want: 30},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 5, want: 50},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 5, want: 50},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 7, want: 70},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 7, want: 70},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 9, want: 90},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 9, want: 90},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 10, want: 100},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 10, want: 100},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 11, want: 110},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 11, want: 110},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 13, want: 130},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 13, want: 130},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 19, want: 190},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 19, want: 190},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 21, want: 210},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 21, want: 210},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 25, want: 250},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 25, want: 250},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 27, want: 270},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 27, want: 270},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 37, want: 370},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 37, want: 370},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 41, want: 410},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 41, want: 410},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 45, want: 450},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 45, want: 450},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 73, want: 730},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 73, want: 730},
+ test_int64{fn: mul_10_int64, fnname: "mul_10_int64", in: 81, want: 810},
+ test_int64{fn: mul_int64_10, fnname: "mul_int64_10", in: 81, want: 810},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: -9, want: -99},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: -9, want: -99},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: -5, want: -55},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: -5, want: -55},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: -3, want: -33},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: -3, want: -33},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 3, want: 33},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 3, want: 33},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 5, want: 55},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 5, want: 55},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 7, want: 77},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 7, want: 77},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 9, want: 99},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 9, want: 99},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 10, want: 110},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 10, want: 110},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 11, want: 121},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 11, want: 121},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 13, want: 143},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 13, want: 143},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 19, want: 209},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 19, want: 209},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 21, want: 231},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 21, want: 231},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 25, want: 275},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 25, want: 275},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 27, want: 297},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 27, want: 297},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 37, want: 407},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 37, want: 407},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 41, want: 451},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 41, want: 451},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 45, want: 495},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 45, want: 495},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 73, want: 803},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 73, want: 803},
+ test_int64{fn: mul_11_int64, fnname: "mul_11_int64", in: 81, want: 891},
+ test_int64{fn: mul_int64_11, fnname: "mul_int64_11", in: 81, want: 891},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: -9, want: -117},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: -9, want: -117},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: -5, want: -65},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: -5, want: -65},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: -3, want: -39},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: -3, want: -39},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 3, want: 39},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 3, want: 39},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 5, want: 65},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 5, want: 65},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 7, want: 91},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 7, want: 91},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 9, want: 117},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 9, want: 117},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 10, want: 130},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 10, want: 130},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 11, want: 143},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 11, want: 143},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 13, want: 169},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 13, want: 169},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 19, want: 247},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 19, want: 247},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 21, want: 273},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 21, want: 273},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 25, want: 325},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 25, want: 325},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 27, want: 351},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 27, want: 351},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 37, want: 481},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 37, want: 481},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 41, want: 533},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 41, want: 533},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 45, want: 585},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 45, want: 585},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 73, want: 949},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 73, want: 949},
+ test_int64{fn: mul_13_int64, fnname: "mul_13_int64", in: 81, want: 1053},
+ test_int64{fn: mul_int64_13, fnname: "mul_int64_13", in: 81, want: 1053},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: -9, want: -171},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: -9, want: -171},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: -5, want: -95},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: -5, want: -95},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: -3, want: -57},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: -3, want: -57},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 3, want: 57},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 3, want: 57},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 5, want: 95},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 5, want: 95},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 7, want: 133},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 7, want: 133},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 9, want: 171},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 9, want: 171},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 10, want: 190},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 10, want: 190},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 11, want: 209},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 11, want: 209},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 13, want: 247},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 13, want: 247},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 19, want: 361},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 19, want: 361},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 21, want: 399},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 21, want: 399},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 25, want: 475},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 25, want: 475},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 27, want: 513},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 27, want: 513},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 37, want: 703},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 37, want: 703},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 41, want: 779},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 41, want: 779},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 45, want: 855},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 45, want: 855},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 73, want: 1387},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 73, want: 1387},
+ test_int64{fn: mul_19_int64, fnname: "mul_19_int64", in: 81, want: 1539},
+ test_int64{fn: mul_int64_19, fnname: "mul_int64_19", in: 81, want: 1539},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: -9, want: -189},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: -9, want: -189},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: -5, want: -105},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: -5, want: -105},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: -3, want: -63},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: -3, want: -63},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 3, want: 63},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 3, want: 63},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 5, want: 105},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 5, want: 105},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 7, want: 147},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 7, want: 147},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 9, want: 189},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 9, want: 189},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 10, want: 210},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 10, want: 210},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 11, want: 231},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 11, want: 231},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 13, want: 273},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 13, want: 273},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 19, want: 399},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 19, want: 399},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 21, want: 441},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 21, want: 441},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 25, want: 525},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 25, want: 525},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 27, want: 567},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 27, want: 567},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 37, want: 777},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 37, want: 777},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 41, want: 861},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 41, want: 861},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 45, want: 945},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 45, want: 945},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 73, want: 1533},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 73, want: 1533},
+ test_int64{fn: mul_21_int64, fnname: "mul_21_int64", in: 81, want: 1701},
+ test_int64{fn: mul_int64_21, fnname: "mul_int64_21", in: 81, want: 1701},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: -9, want: -225},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: -9, want: -225},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: -5, want: -125},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: -5, want: -125},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: -3, want: -75},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: -3, want: -75},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 3, want: 75},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 3, want: 75},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 5, want: 125},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 5, want: 125},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 7, want: 175},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 7, want: 175},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 9, want: 225},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 9, want: 225},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 10, want: 250},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 10, want: 250},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 11, want: 275},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 11, want: 275},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 13, want: 325},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 13, want: 325},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 19, want: 475},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 19, want: 475},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 21, want: 525},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 21, want: 525},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 25, want: 625},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 25, want: 625},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 27, want: 675},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 27, want: 675},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 37, want: 925},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 37, want: 925},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 41, want: 1025},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 41, want: 1025},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 45, want: 1125},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 45, want: 1125},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 73, want: 1825},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 73, want: 1825},
+ test_int64{fn: mul_25_int64, fnname: "mul_25_int64", in: 81, want: 2025},
+ test_int64{fn: mul_int64_25, fnname: "mul_int64_25", in: 81, want: 2025},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: -9, want: -243},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: -9, want: -243},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: -5, want: -135},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: -5, want: -135},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: -3, want: -81},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: -3, want: -81},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 3, want: 81},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 3, want: 81},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 5, want: 135},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 5, want: 135},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 7, want: 189},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 7, want: 189},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 9, want: 243},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 9, want: 243},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 10, want: 270},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 10, want: 270},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 11, want: 297},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 11, want: 297},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 13, want: 351},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 13, want: 351},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 19, want: 513},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 19, want: 513},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 21, want: 567},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 21, want: 567},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 25, want: 675},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 25, want: 675},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 27, want: 729},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 27, want: 729},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 37, want: 999},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 37, want: 999},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 41, want: 1107},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 41, want: 1107},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 45, want: 1215},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 45, want: 1215},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 73, want: 1971},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 73, want: 1971},
+ test_int64{fn: mul_27_int64, fnname: "mul_27_int64", in: 81, want: 2187},
+ test_int64{fn: mul_int64_27, fnname: "mul_int64_27", in: 81, want: 2187},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: -9, want: -333},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: -9, want: -333},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: -5, want: -185},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: -5, want: -185},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: -3, want: -111},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: -3, want: -111},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 3, want: 111},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 3, want: 111},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 5, want: 185},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 5, want: 185},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 7, want: 259},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 7, want: 259},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 9, want: 333},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 9, want: 333},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 10, want: 370},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 10, want: 370},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 11, want: 407},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 11, want: 407},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 13, want: 481},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 13, want: 481},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 19, want: 703},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 19, want: 703},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 21, want: 777},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 21, want: 777},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 25, want: 925},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 25, want: 925},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 27, want: 999},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 27, want: 999},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 37, want: 1369},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 37, want: 1369},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 41, want: 1517},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 41, want: 1517},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 45, want: 1665},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 45, want: 1665},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 73, want: 2701},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 73, want: 2701},
+ test_int64{fn: mul_37_int64, fnname: "mul_37_int64", in: 81, want: 2997},
+ test_int64{fn: mul_int64_37, fnname: "mul_int64_37", in: 81, want: 2997},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: -9, want: -369},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: -9, want: -369},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: -5, want: -205},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: -5, want: -205},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: -3, want: -123},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: -3, want: -123},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 3, want: 123},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 3, want: 123},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 5, want: 205},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 5, want: 205},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 7, want: 287},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 7, want: 287},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 9, want: 369},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 9, want: 369},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 10, want: 410},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 10, want: 410},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 11, want: 451},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 11, want: 451},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 13, want: 533},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 13, want: 533},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 19, want: 779},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 19, want: 779},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 21, want: 861},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 21, want: 861},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 25, want: 1025},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 25, want: 1025},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 27, want: 1107},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 27, want: 1107},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 37, want: 1517},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 37, want: 1517},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 41, want: 1681},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 41, want: 1681},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 45, want: 1845},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 45, want: 1845},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 73, want: 2993},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 73, want: 2993},
+ test_int64{fn: mul_41_int64, fnname: "mul_41_int64", in: 81, want: 3321},
+ test_int64{fn: mul_int64_41, fnname: "mul_int64_41", in: 81, want: 3321},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: -9, want: -405},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: -9, want: -405},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: -5, want: -225},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: -5, want: -225},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: -3, want: -135},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: -3, want: -135},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 3, want: 135},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 3, want: 135},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 5, want: 225},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 5, want: 225},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 7, want: 315},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 7, want: 315},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 9, want: 405},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 9, want: 405},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 10, want: 450},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 10, want: 450},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 11, want: 495},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 11, want: 495},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 13, want: 585},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 13, want: 585},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 19, want: 855},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 19, want: 855},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 21, want: 945},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 21, want: 945},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 25, want: 1125},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 25, want: 1125},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 27, want: 1215},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 27, want: 1215},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 37, want: 1665},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 37, want: 1665},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 41, want: 1845},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 41, want: 1845},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 45, want: 2025},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 45, want: 2025},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 73, want: 3285},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 73, want: 3285},
+ test_int64{fn: mul_45_int64, fnname: "mul_45_int64", in: 81, want: 3645},
+ test_int64{fn: mul_int64_45, fnname: "mul_int64_45", in: 81, want: 3645},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: -9, want: -657},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: -9, want: -657},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: -5, want: -365},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: -5, want: -365},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: -3, want: -219},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: -3, want: -219},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 3, want: 219},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 3, want: 219},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 5, want: 365},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 5, want: 365},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 7, want: 511},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 7, want: 511},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 9, want: 657},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 9, want: 657},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 10, want: 730},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 10, want: 730},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 11, want: 803},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 11, want: 803},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 13, want: 949},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 13, want: 949},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 19, want: 1387},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 19, want: 1387},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 21, want: 1533},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 21, want: 1533},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 25, want: 1825},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 25, want: 1825},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 27, want: 1971},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 27, want: 1971},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 37, want: 2701},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 37, want: 2701},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 41, want: 2993},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 41, want: 2993},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 45, want: 3285},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 45, want: 3285},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 73, want: 5329},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 73, want: 5329},
+ test_int64{fn: mul_73_int64, fnname: "mul_73_int64", in: 81, want: 5913},
+ test_int64{fn: mul_int64_73, fnname: "mul_int64_73", in: 81, want: 5913},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: -9, want: -729},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: -9, want: -729},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: -5, want: -405},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: -5, want: -405},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: -3, want: -243},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: -3, want: -243},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 3, want: 243},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 3, want: 243},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 5, want: 405},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 5, want: 405},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 7, want: 567},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 7, want: 567},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 9, want: 729},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 9, want: 729},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 10, want: 810},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 10, want: 810},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 11, want: 891},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 11, want: 891},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 13, want: 1053},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 13, want: 1053},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 19, want: 1539},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 19, want: 1539},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 21, want: 1701},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 21, want: 1701},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 25, want: 2025},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 25, want: 2025},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 27, want: 2187},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 27, want: 2187},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 37, want: 2997},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 37, want: 2997},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 41, want: 3321},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 41, want: 3321},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 45, want: 3645},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 45, want: 3645},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 73, want: 5913},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 73, want: 5913},
+ test_int64{fn: mul_81_int64, fnname: "mul_81_int64", in: 81, want: 6561},
+ test_int64{fn: mul_int64_81, fnname: "mul_int64_81", in: 81, want: 6561}}
+
+type test_uint32 struct {
+ fn func(uint32) uint32
+ fnname string
+ in uint32
+ want uint32
+}
+
+var tests_uint32 = []test_uint32{
+
+ test_uint32{fn: add_0_uint32, fnname: "add_0_uint32", in: 0, want: 0},
+ test_uint32{fn: add_uint32_0, fnname: "add_uint32_0", in: 0, want: 0},
+ test_uint32{fn: add_0_uint32, fnname: "add_0_uint32", in: 1, want: 1},
+ test_uint32{fn: add_uint32_0, fnname: "add_uint32_0", in: 1, want: 1},
+ test_uint32{fn: add_0_uint32, fnname: "add_0_uint32", in: 4294967295, want: 4294967295},
+ test_uint32{fn: add_uint32_0, fnname: "add_uint32_0", in: 4294967295, want: 4294967295},
+ test_uint32{fn: add_1_uint32, fnname: "add_1_uint32", in: 0, want: 1},
+ test_uint32{fn: add_uint32_1, fnname: "add_uint32_1", in: 0, want: 1},
+ test_uint32{fn: add_1_uint32, fnname: "add_1_uint32", in: 1, want: 2},
+ test_uint32{fn: add_uint32_1, fnname: "add_uint32_1", in: 1, want: 2},
+ test_uint32{fn: add_1_uint32, fnname: "add_1_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: add_uint32_1, fnname: "add_uint32_1", in: 4294967295, want: 0},
+ test_uint32{fn: add_4294967295_uint32, fnname: "add_4294967295_uint32", in: 0, want: 4294967295},
+ test_uint32{fn: add_uint32_4294967295, fnname: "add_uint32_4294967295", in: 0, want: 4294967295},
+ test_uint32{fn: add_4294967295_uint32, fnname: "add_4294967295_uint32", in: 1, want: 0},
+ test_uint32{fn: add_uint32_4294967295, fnname: "add_uint32_4294967295", in: 1, want: 0},
+ test_uint32{fn: add_4294967295_uint32, fnname: "add_4294967295_uint32", in: 4294967295, want: 4294967294},
+ test_uint32{fn: add_uint32_4294967295, fnname: "add_uint32_4294967295", in: 4294967295, want: 4294967294},
+ test_uint32{fn: sub_0_uint32, fnname: "sub_0_uint32", in: 0, want: 0},
+ test_uint32{fn: sub_uint32_0, fnname: "sub_uint32_0", in: 0, want: 0},
+ test_uint32{fn: sub_0_uint32, fnname: "sub_0_uint32", in: 1, want: 4294967295},
+ test_uint32{fn: sub_uint32_0, fnname: "sub_uint32_0", in: 1, want: 1},
+ test_uint32{fn: sub_0_uint32, fnname: "sub_0_uint32", in: 4294967295, want: 1},
+ test_uint32{fn: sub_uint32_0, fnname: "sub_uint32_0", in: 4294967295, want: 4294967295},
+ test_uint32{fn: sub_1_uint32, fnname: "sub_1_uint32", in: 0, want: 1},
+ test_uint32{fn: sub_uint32_1, fnname: "sub_uint32_1", in: 0, want: 4294967295},
+ test_uint32{fn: sub_1_uint32, fnname: "sub_1_uint32", in: 1, want: 0},
+ test_uint32{fn: sub_uint32_1, fnname: "sub_uint32_1", in: 1, want: 0},
+ test_uint32{fn: sub_1_uint32, fnname: "sub_1_uint32", in: 4294967295, want: 2},
+ test_uint32{fn: sub_uint32_1, fnname: "sub_uint32_1", in: 4294967295, want: 4294967294},
+ test_uint32{fn: sub_4294967295_uint32, fnname: "sub_4294967295_uint32", in: 0, want: 4294967295},
+ test_uint32{fn: sub_uint32_4294967295, fnname: "sub_uint32_4294967295", in: 0, want: 1},
+ test_uint32{fn: sub_4294967295_uint32, fnname: "sub_4294967295_uint32", in: 1, want: 4294967294},
+ test_uint32{fn: sub_uint32_4294967295, fnname: "sub_uint32_4294967295", in: 1, want: 2},
+ test_uint32{fn: sub_4294967295_uint32, fnname: "sub_4294967295_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: sub_uint32_4294967295, fnname: "sub_uint32_4294967295", in: 4294967295, want: 0},
+ test_uint32{fn: div_0_uint32, fnname: "div_0_uint32", in: 1, want: 0},
+ test_uint32{fn: div_0_uint32, fnname: "div_0_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: div_uint32_1, fnname: "div_uint32_1", in: 0, want: 0},
+ test_uint32{fn: div_1_uint32, fnname: "div_1_uint32", in: 1, want: 1},
+ test_uint32{fn: div_uint32_1, fnname: "div_uint32_1", in: 1, want: 1},
+ test_uint32{fn: div_1_uint32, fnname: "div_1_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: div_uint32_1, fnname: "div_uint32_1", in: 4294967295, want: 4294967295},
+ test_uint32{fn: div_uint32_4294967295, fnname: "div_uint32_4294967295", in: 0, want: 0},
+ test_uint32{fn: div_4294967295_uint32, fnname: "div_4294967295_uint32", in: 1, want: 4294967295},
+ test_uint32{fn: div_uint32_4294967295, fnname: "div_uint32_4294967295", in: 1, want: 0},
+ test_uint32{fn: div_4294967295_uint32, fnname: "div_4294967295_uint32", in: 4294967295, want: 1},
+ test_uint32{fn: div_uint32_4294967295, fnname: "div_uint32_4294967295", in: 4294967295, want: 1},
+ test_uint32{fn: mul_0_uint32, fnname: "mul_0_uint32", in: 0, want: 0},
+ test_uint32{fn: mul_uint32_0, fnname: "mul_uint32_0", in: 0, want: 0},
+ test_uint32{fn: mul_0_uint32, fnname: "mul_0_uint32", in: 1, want: 0},
+ test_uint32{fn: mul_uint32_0, fnname: "mul_uint32_0", in: 1, want: 0},
+ test_uint32{fn: mul_0_uint32, fnname: "mul_0_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: mul_uint32_0, fnname: "mul_uint32_0", in: 4294967295, want: 0},
+ test_uint32{fn: mul_1_uint32, fnname: "mul_1_uint32", in: 0, want: 0},
+ test_uint32{fn: mul_uint32_1, fnname: "mul_uint32_1", in: 0, want: 0},
+ test_uint32{fn: mul_1_uint32, fnname: "mul_1_uint32", in: 1, want: 1},
+ test_uint32{fn: mul_uint32_1, fnname: "mul_uint32_1", in: 1, want: 1},
+ test_uint32{fn: mul_1_uint32, fnname: "mul_1_uint32", in: 4294967295, want: 4294967295},
+ test_uint32{fn: mul_uint32_1, fnname: "mul_uint32_1", in: 4294967295, want: 4294967295},
+ test_uint32{fn: mul_4294967295_uint32, fnname: "mul_4294967295_uint32", in: 0, want: 0},
+ test_uint32{fn: mul_uint32_4294967295, fnname: "mul_uint32_4294967295", in: 0, want: 0},
+ test_uint32{fn: mul_4294967295_uint32, fnname: "mul_4294967295_uint32", in: 1, want: 4294967295},
+ test_uint32{fn: mul_uint32_4294967295, fnname: "mul_uint32_4294967295", in: 1, want: 4294967295},
+ test_uint32{fn: mul_4294967295_uint32, fnname: "mul_4294967295_uint32", in: 4294967295, want: 1},
+ test_uint32{fn: mul_uint32_4294967295, fnname: "mul_uint32_4294967295", in: 4294967295, want: 1},
+ test_uint32{fn: lsh_0_uint32, fnname: "lsh_0_uint32", in: 0, want: 0},
+ test_uint32{fn: lsh_uint32_0, fnname: "lsh_uint32_0", in: 0, want: 0},
+ test_uint32{fn: lsh_0_uint32, fnname: "lsh_0_uint32", in: 1, want: 0},
+ test_uint32{fn: lsh_uint32_0, fnname: "lsh_uint32_0", in: 1, want: 1},
+ test_uint32{fn: lsh_0_uint32, fnname: "lsh_0_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: lsh_uint32_0, fnname: "lsh_uint32_0", in: 4294967295, want: 4294967295},
+ test_uint32{fn: lsh_1_uint32, fnname: "lsh_1_uint32", in: 0, want: 1},
+ test_uint32{fn: lsh_uint32_1, fnname: "lsh_uint32_1", in: 0, want: 0},
+ test_uint32{fn: lsh_1_uint32, fnname: "lsh_1_uint32", in: 1, want: 2},
+ test_uint32{fn: lsh_uint32_1, fnname: "lsh_uint32_1", in: 1, want: 2},
+ test_uint32{fn: lsh_1_uint32, fnname: "lsh_1_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: lsh_uint32_1, fnname: "lsh_uint32_1", in: 4294967295, want: 4294967294},
+ test_uint32{fn: lsh_4294967295_uint32, fnname: "lsh_4294967295_uint32", in: 0, want: 4294967295},
+ test_uint32{fn: lsh_uint32_4294967295, fnname: "lsh_uint32_4294967295", in: 0, want: 0},
+ test_uint32{fn: lsh_4294967295_uint32, fnname: "lsh_4294967295_uint32", in: 1, want: 4294967294},
+ test_uint32{fn: lsh_uint32_4294967295, fnname: "lsh_uint32_4294967295", in: 1, want: 0},
+ test_uint32{fn: lsh_4294967295_uint32, fnname: "lsh_4294967295_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: lsh_uint32_4294967295, fnname: "lsh_uint32_4294967295", in: 4294967295, want: 0},
+ test_uint32{fn: rsh_0_uint32, fnname: "rsh_0_uint32", in: 0, want: 0},
+ test_uint32{fn: rsh_uint32_0, fnname: "rsh_uint32_0", in: 0, want: 0},
+ test_uint32{fn: rsh_0_uint32, fnname: "rsh_0_uint32", in: 1, want: 0},
+ test_uint32{fn: rsh_uint32_0, fnname: "rsh_uint32_0", in: 1, want: 1},
+ test_uint32{fn: rsh_0_uint32, fnname: "rsh_0_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: rsh_uint32_0, fnname: "rsh_uint32_0", in: 4294967295, want: 4294967295},
+ test_uint32{fn: rsh_1_uint32, fnname: "rsh_1_uint32", in: 0, want: 1},
+ test_uint32{fn: rsh_uint32_1, fnname: "rsh_uint32_1", in: 0, want: 0},
+ test_uint32{fn: rsh_1_uint32, fnname: "rsh_1_uint32", in: 1, want: 0},
+ test_uint32{fn: rsh_uint32_1, fnname: "rsh_uint32_1", in: 1, want: 0},
+ test_uint32{fn: rsh_1_uint32, fnname: "rsh_1_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: rsh_uint32_1, fnname: "rsh_uint32_1", in: 4294967295, want: 2147483647},
+ test_uint32{fn: rsh_4294967295_uint32, fnname: "rsh_4294967295_uint32", in: 0, want: 4294967295},
+ test_uint32{fn: rsh_uint32_4294967295, fnname: "rsh_uint32_4294967295", in: 0, want: 0},
+ test_uint32{fn: rsh_4294967295_uint32, fnname: "rsh_4294967295_uint32", in: 1, want: 2147483647},
+ test_uint32{fn: rsh_uint32_4294967295, fnname: "rsh_uint32_4294967295", in: 1, want: 0},
+ test_uint32{fn: rsh_4294967295_uint32, fnname: "rsh_4294967295_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: rsh_uint32_4294967295, fnname: "rsh_uint32_4294967295", in: 4294967295, want: 0},
+ test_uint32{fn: mod_0_uint32, fnname: "mod_0_uint32", in: 1, want: 0},
+ test_uint32{fn: mod_0_uint32, fnname: "mod_0_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: mod_uint32_1, fnname: "mod_uint32_1", in: 0, want: 0},
+ test_uint32{fn: mod_1_uint32, fnname: "mod_1_uint32", in: 1, want: 0},
+ test_uint32{fn: mod_uint32_1, fnname: "mod_uint32_1", in: 1, want: 0},
+ test_uint32{fn: mod_1_uint32, fnname: "mod_1_uint32", in: 4294967295, want: 1},
+ test_uint32{fn: mod_uint32_1, fnname: "mod_uint32_1", in: 4294967295, want: 0},
+ test_uint32{fn: mod_uint32_4294967295, fnname: "mod_uint32_4294967295", in: 0, want: 0},
+ test_uint32{fn: mod_4294967295_uint32, fnname: "mod_4294967295_uint32", in: 1, want: 0},
+ test_uint32{fn: mod_uint32_4294967295, fnname: "mod_uint32_4294967295", in: 1, want: 1},
+ test_uint32{fn: mod_4294967295_uint32, fnname: "mod_4294967295_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: mod_uint32_4294967295, fnname: "mod_uint32_4294967295", in: 4294967295, want: 0},
+ test_uint32{fn: and_0_uint32, fnname: "and_0_uint32", in: 0, want: 0},
+ test_uint32{fn: and_uint32_0, fnname: "and_uint32_0", in: 0, want: 0},
+ test_uint32{fn: and_0_uint32, fnname: "and_0_uint32", in: 1, want: 0},
+ test_uint32{fn: and_uint32_0, fnname: "and_uint32_0", in: 1, want: 0},
+ test_uint32{fn: and_0_uint32, fnname: "and_0_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: and_uint32_0, fnname: "and_uint32_0", in: 4294967295, want: 0},
+ test_uint32{fn: and_1_uint32, fnname: "and_1_uint32", in: 0, want: 0},
+ test_uint32{fn: and_uint32_1, fnname: "and_uint32_1", in: 0, want: 0},
+ test_uint32{fn: and_1_uint32, fnname: "and_1_uint32", in: 1, want: 1},
+ test_uint32{fn: and_uint32_1, fnname: "and_uint32_1", in: 1, want: 1},
+ test_uint32{fn: and_1_uint32, fnname: "and_1_uint32", in: 4294967295, want: 1},
+ test_uint32{fn: and_uint32_1, fnname: "and_uint32_1", in: 4294967295, want: 1},
+ test_uint32{fn: and_4294967295_uint32, fnname: "and_4294967295_uint32", in: 0, want: 0},
+ test_uint32{fn: and_uint32_4294967295, fnname: "and_uint32_4294967295", in: 0, want: 0},
+ test_uint32{fn: and_4294967295_uint32, fnname: "and_4294967295_uint32", in: 1, want: 1},
+ test_uint32{fn: and_uint32_4294967295, fnname: "and_uint32_4294967295", in: 1, want: 1},
+ test_uint32{fn: and_4294967295_uint32, fnname: "and_4294967295_uint32", in: 4294967295, want: 4294967295},
+ test_uint32{fn: and_uint32_4294967295, fnname: "and_uint32_4294967295", in: 4294967295, want: 4294967295},
+ test_uint32{fn: or_0_uint32, fnname: "or_0_uint32", in: 0, want: 0},
+ test_uint32{fn: or_uint32_0, fnname: "or_uint32_0", in: 0, want: 0},
+ test_uint32{fn: or_0_uint32, fnname: "or_0_uint32", in: 1, want: 1},
+ test_uint32{fn: or_uint32_0, fnname: "or_uint32_0", in: 1, want: 1},
+ test_uint32{fn: or_0_uint32, fnname: "or_0_uint32", in: 4294967295, want: 4294967295},
+ test_uint32{fn: or_uint32_0, fnname: "or_uint32_0", in: 4294967295, want: 4294967295},
+ test_uint32{fn: or_1_uint32, fnname: "or_1_uint32", in: 0, want: 1},
+ test_uint32{fn: or_uint32_1, fnname: "or_uint32_1", in: 0, want: 1},
+ test_uint32{fn: or_1_uint32, fnname: "or_1_uint32", in: 1, want: 1},
+ test_uint32{fn: or_uint32_1, fnname: "or_uint32_1", in: 1, want: 1},
+ test_uint32{fn: or_1_uint32, fnname: "or_1_uint32", in: 4294967295, want: 4294967295},
+ test_uint32{fn: or_uint32_1, fnname: "or_uint32_1", in: 4294967295, want: 4294967295},
+ test_uint32{fn: or_4294967295_uint32, fnname: "or_4294967295_uint32", in: 0, want: 4294967295},
+ test_uint32{fn: or_uint32_4294967295, fnname: "or_uint32_4294967295", in: 0, want: 4294967295},
+ test_uint32{fn: or_4294967295_uint32, fnname: "or_4294967295_uint32", in: 1, want: 4294967295},
+ test_uint32{fn: or_uint32_4294967295, fnname: "or_uint32_4294967295", in: 1, want: 4294967295},
+ test_uint32{fn: or_4294967295_uint32, fnname: "or_4294967295_uint32", in: 4294967295, want: 4294967295},
+ test_uint32{fn: or_uint32_4294967295, fnname: "or_uint32_4294967295", in: 4294967295, want: 4294967295},
+ test_uint32{fn: xor_0_uint32, fnname: "xor_0_uint32", in: 0, want: 0},
+ test_uint32{fn: xor_uint32_0, fnname: "xor_uint32_0", in: 0, want: 0},
+ test_uint32{fn: xor_0_uint32, fnname: "xor_0_uint32", in: 1, want: 1},
+ test_uint32{fn: xor_uint32_0, fnname: "xor_uint32_0", in: 1, want: 1},
+ test_uint32{fn: xor_0_uint32, fnname: "xor_0_uint32", in: 4294967295, want: 4294967295},
+ test_uint32{fn: xor_uint32_0, fnname: "xor_uint32_0", in: 4294967295, want: 4294967295},
+ test_uint32{fn: xor_1_uint32, fnname: "xor_1_uint32", in: 0, want: 1},
+ test_uint32{fn: xor_uint32_1, fnname: "xor_uint32_1", in: 0, want: 1},
+ test_uint32{fn: xor_1_uint32, fnname: "xor_1_uint32", in: 1, want: 0},
+ test_uint32{fn: xor_uint32_1, fnname: "xor_uint32_1", in: 1, want: 0},
+ test_uint32{fn: xor_1_uint32, fnname: "xor_1_uint32", in: 4294967295, want: 4294967294},
+ test_uint32{fn: xor_uint32_1, fnname: "xor_uint32_1", in: 4294967295, want: 4294967294},
+ test_uint32{fn: xor_4294967295_uint32, fnname: "xor_4294967295_uint32", in: 0, want: 4294967295},
+ test_uint32{fn: xor_uint32_4294967295, fnname: "xor_uint32_4294967295", in: 0, want: 4294967295},
+ test_uint32{fn: xor_4294967295_uint32, fnname: "xor_4294967295_uint32", in: 1, want: 4294967294},
+ test_uint32{fn: xor_uint32_4294967295, fnname: "xor_uint32_4294967295", in: 1, want: 4294967294},
+ test_uint32{fn: xor_4294967295_uint32, fnname: "xor_4294967295_uint32", in: 4294967295, want: 0},
+ test_uint32{fn: xor_uint32_4294967295, fnname: "xor_uint32_4294967295", in: 4294967295, want: 0}}
+
+type test_uint32mul struct {
+ fn func(uint32) uint32
+ fnname string
+ in uint32
+ want uint32
+}
+
+var tests_uint32mul = []test_uint32{
+
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 3, want: 9},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 3, want: 9},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 5, want: 15},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 5, want: 15},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 7, want: 21},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 7, want: 21},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 9, want: 27},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 9, want: 27},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 10, want: 30},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 10, want: 30},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 11, want: 33},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 11, want: 33},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 13, want: 39},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 13, want: 39},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 19, want: 57},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 19, want: 57},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 21, want: 63},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 21, want: 63},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 25, want: 75},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 25, want: 75},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 27, want: 81},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 27, want: 81},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 37, want: 111},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 37, want: 111},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 41, want: 123},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 41, want: 123},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 45, want: 135},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 45, want: 135},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 73, want: 219},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 73, want: 219},
+ test_uint32{fn: mul_3_uint32, fnname: "mul_3_uint32", in: 81, want: 243},
+ test_uint32{fn: mul_uint32_3, fnname: "mul_uint32_3", in: 81, want: 243},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 3, want: 15},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 3, want: 15},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 5, want: 25},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 5, want: 25},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 7, want: 35},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 7, want: 35},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 9, want: 45},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 9, want: 45},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 10, want: 50},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 10, want: 50},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 11, want: 55},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 11, want: 55},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 13, want: 65},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 13, want: 65},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 19, want: 95},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 19, want: 95},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 21, want: 105},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 21, want: 105},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 25, want: 125},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 25, want: 125},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 27, want: 135},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 27, want: 135},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 37, want: 185},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 37, want: 185},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 41, want: 205},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 41, want: 205},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 45, want: 225},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 45, want: 225},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 73, want: 365},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 73, want: 365},
+ test_uint32{fn: mul_5_uint32, fnname: "mul_5_uint32", in: 81, want: 405},
+ test_uint32{fn: mul_uint32_5, fnname: "mul_uint32_5", in: 81, want: 405},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 3, want: 21},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 3, want: 21},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 5, want: 35},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 5, want: 35},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 7, want: 49},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 7, want: 49},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 9, want: 63},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 9, want: 63},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 10, want: 70},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 10, want: 70},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 11, want: 77},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 11, want: 77},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 13, want: 91},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 13, want: 91},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 19, want: 133},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 19, want: 133},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 21, want: 147},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 21, want: 147},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 25, want: 175},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 25, want: 175},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 27, want: 189},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 27, want: 189},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 37, want: 259},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 37, want: 259},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 41, want: 287},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 41, want: 287},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 45, want: 315},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 45, want: 315},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 73, want: 511},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 73, want: 511},
+ test_uint32{fn: mul_7_uint32, fnname: "mul_7_uint32", in: 81, want: 567},
+ test_uint32{fn: mul_uint32_7, fnname: "mul_uint32_7", in: 81, want: 567},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 3, want: 27},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 3, want: 27},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 5, want: 45},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 5, want: 45},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 7, want: 63},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 7, want: 63},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 9, want: 81},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 9, want: 81},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 10, want: 90},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 10, want: 90},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 11, want: 99},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 11, want: 99},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 13, want: 117},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 13, want: 117},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 19, want: 171},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 19, want: 171},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 21, want: 189},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 21, want: 189},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 25, want: 225},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 25, want: 225},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 27, want: 243},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 27, want: 243},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 37, want: 333},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 37, want: 333},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 41, want: 369},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 41, want: 369},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 45, want: 405},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 45, want: 405},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 73, want: 657},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 73, want: 657},
+ test_uint32{fn: mul_9_uint32, fnname: "mul_9_uint32", in: 81, want: 729},
+ test_uint32{fn: mul_uint32_9, fnname: "mul_uint32_9", in: 81, want: 729},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 3, want: 30},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 3, want: 30},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 5, want: 50},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 5, want: 50},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 7, want: 70},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 7, want: 70},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 9, want: 90},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 9, want: 90},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 10, want: 100},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 10, want: 100},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 11, want: 110},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 11, want: 110},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 13, want: 130},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 13, want: 130},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 19, want: 190},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 19, want: 190},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 21, want: 210},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 21, want: 210},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 25, want: 250},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 25, want: 250},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 27, want: 270},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 27, want: 270},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 37, want: 370},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 37, want: 370},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 41, want: 410},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 41, want: 410},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 45, want: 450},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 45, want: 450},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 73, want: 730},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 73, want: 730},
+ test_uint32{fn: mul_10_uint32, fnname: "mul_10_uint32", in: 81, want: 810},
+ test_uint32{fn: mul_uint32_10, fnname: "mul_uint32_10", in: 81, want: 810},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 3, want: 33},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 3, want: 33},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 5, want: 55},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 5, want: 55},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 7, want: 77},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 7, want: 77},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 9, want: 99},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 9, want: 99},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 10, want: 110},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 10, want: 110},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 11, want: 121},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 11, want: 121},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 13, want: 143},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 13, want: 143},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 19, want: 209},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 19, want: 209},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 21, want: 231},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 21, want: 231},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 25, want: 275},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 25, want: 275},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 27, want: 297},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 27, want: 297},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 37, want: 407},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 37, want: 407},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 41, want: 451},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 41, want: 451},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 45, want: 495},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 45, want: 495},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 73, want: 803},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 73, want: 803},
+ test_uint32{fn: mul_11_uint32, fnname: "mul_11_uint32", in: 81, want: 891},
+ test_uint32{fn: mul_uint32_11, fnname: "mul_uint32_11", in: 81, want: 891},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 3, want: 39},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 3, want: 39},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 5, want: 65},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 5, want: 65},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 7, want: 91},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 7, want: 91},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 9, want: 117},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 9, want: 117},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 10, want: 130},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 10, want: 130},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 11, want: 143},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 11, want: 143},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 13, want: 169},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 13, want: 169},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 19, want: 247},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 19, want: 247},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 21, want: 273},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 21, want: 273},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 25, want: 325},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 25, want: 325},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 27, want: 351},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 27, want: 351},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 37, want: 481},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 37, want: 481},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 41, want: 533},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 41, want: 533},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 45, want: 585},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 45, want: 585},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 73, want: 949},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 73, want: 949},
+ test_uint32{fn: mul_13_uint32, fnname: "mul_13_uint32", in: 81, want: 1053},
+ test_uint32{fn: mul_uint32_13, fnname: "mul_uint32_13", in: 81, want: 1053},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 3, want: 57},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 3, want: 57},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 5, want: 95},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 5, want: 95},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 7, want: 133},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 7, want: 133},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 9, want: 171},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 9, want: 171},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 10, want: 190},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 10, want: 190},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 11, want: 209},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 11, want: 209},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 13, want: 247},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 13, want: 247},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 19, want: 361},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 19, want: 361},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 21, want: 399},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 21, want: 399},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 25, want: 475},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 25, want: 475},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 27, want: 513},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 27, want: 513},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 37, want: 703},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 37, want: 703},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 41, want: 779},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 41, want: 779},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 45, want: 855},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 45, want: 855},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 73, want: 1387},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 73, want: 1387},
+ test_uint32{fn: mul_19_uint32, fnname: "mul_19_uint32", in: 81, want: 1539},
+ test_uint32{fn: mul_uint32_19, fnname: "mul_uint32_19", in: 81, want: 1539},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 3, want: 63},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 3, want: 63},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 5, want: 105},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 5, want: 105},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 7, want: 147},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 7, want: 147},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 9, want: 189},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 9, want: 189},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 10, want: 210},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 10, want: 210},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 11, want: 231},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 11, want: 231},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 13, want: 273},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 13, want: 273},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 19, want: 399},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 19, want: 399},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 21, want: 441},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 21, want: 441},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 25, want: 525},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 25, want: 525},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 27, want: 567},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 27, want: 567},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 37, want: 777},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 37, want: 777},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 41, want: 861},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 41, want: 861},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 45, want: 945},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 45, want: 945},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 73, want: 1533},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 73, want: 1533},
+ test_uint32{fn: mul_21_uint32, fnname: "mul_21_uint32", in: 81, want: 1701},
+ test_uint32{fn: mul_uint32_21, fnname: "mul_uint32_21", in: 81, want: 1701},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 3, want: 75},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 3, want: 75},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 5, want: 125},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 5, want: 125},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 7, want: 175},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 7, want: 175},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 9, want: 225},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 9, want: 225},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 10, want: 250},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 10, want: 250},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 11, want: 275},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 11, want: 275},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 13, want: 325},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 13, want: 325},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 19, want: 475},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 19, want: 475},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 21, want: 525},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 21, want: 525},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 25, want: 625},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 25, want: 625},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 27, want: 675},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 27, want: 675},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 37, want: 925},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 37, want: 925},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 41, want: 1025},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 41, want: 1025},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 45, want: 1125},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 45, want: 1125},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 73, want: 1825},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 73, want: 1825},
+ test_uint32{fn: mul_25_uint32, fnname: "mul_25_uint32", in: 81, want: 2025},
+ test_uint32{fn: mul_uint32_25, fnname: "mul_uint32_25", in: 81, want: 2025},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 3, want: 81},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 3, want: 81},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 5, want: 135},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 5, want: 135},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 7, want: 189},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 7, want: 189},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 9, want: 243},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 9, want: 243},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 10, want: 270},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 10, want: 270},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 11, want: 297},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 11, want: 297},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 13, want: 351},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 13, want: 351},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 19, want: 513},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 19, want: 513},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 21, want: 567},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 21, want: 567},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 25, want: 675},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 25, want: 675},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 27, want: 729},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 27, want: 729},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 37, want: 999},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 37, want: 999},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 41, want: 1107},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 41, want: 1107},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 45, want: 1215},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 45, want: 1215},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 73, want: 1971},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 73, want: 1971},
+ test_uint32{fn: mul_27_uint32, fnname: "mul_27_uint32", in: 81, want: 2187},
+ test_uint32{fn: mul_uint32_27, fnname: "mul_uint32_27", in: 81, want: 2187},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 3, want: 111},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 3, want: 111},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 5, want: 185},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 5, want: 185},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 7, want: 259},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 7, want: 259},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 9, want: 333},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 9, want: 333},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 10, want: 370},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 10, want: 370},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 11, want: 407},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 11, want: 407},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 13, want: 481},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 13, want: 481},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 19, want: 703},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 19, want: 703},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 21, want: 777},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 21, want: 777},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 25, want: 925},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 25, want: 925},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 27, want: 999},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 27, want: 999},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 37, want: 1369},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 37, want: 1369},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 41, want: 1517},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 41, want: 1517},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 45, want: 1665},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 45, want: 1665},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 73, want: 2701},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 73, want: 2701},
+ test_uint32{fn: mul_37_uint32, fnname: "mul_37_uint32", in: 81, want: 2997},
+ test_uint32{fn: mul_uint32_37, fnname: "mul_uint32_37", in: 81, want: 2997},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 3, want: 123},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 3, want: 123},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 5, want: 205},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 5, want: 205},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 7, want: 287},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 7, want: 287},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 9, want: 369},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 9, want: 369},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 10, want: 410},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 10, want: 410},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 11, want: 451},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 11, want: 451},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 13, want: 533},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 13, want: 533},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 19, want: 779},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 19, want: 779},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 21, want: 861},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 21, want: 861},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 25, want: 1025},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 25, want: 1025},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 27, want: 1107},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 27, want: 1107},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 37, want: 1517},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 37, want: 1517},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 41, want: 1681},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 41, want: 1681},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 45, want: 1845},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 45, want: 1845},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 73, want: 2993},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 73, want: 2993},
+ test_uint32{fn: mul_41_uint32, fnname: "mul_41_uint32", in: 81, want: 3321},
+ test_uint32{fn: mul_uint32_41, fnname: "mul_uint32_41", in: 81, want: 3321},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 3, want: 135},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 3, want: 135},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 5, want: 225},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 5, want: 225},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 7, want: 315},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 7, want: 315},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 9, want: 405},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 9, want: 405},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 10, want: 450},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 10, want: 450},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 11, want: 495},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 11, want: 495},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 13, want: 585},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 13, want: 585},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 19, want: 855},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 19, want: 855},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 21, want: 945},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 21, want: 945},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 25, want: 1125},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 25, want: 1125},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 27, want: 1215},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 27, want: 1215},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 37, want: 1665},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 37, want: 1665},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 41, want: 1845},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 41, want: 1845},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 45, want: 2025},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 45, want: 2025},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 73, want: 3285},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 73, want: 3285},
+ test_uint32{fn: mul_45_uint32, fnname: "mul_45_uint32", in: 81, want: 3645},
+ test_uint32{fn: mul_uint32_45, fnname: "mul_uint32_45", in: 81, want: 3645},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 3, want: 219},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 3, want: 219},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 5, want: 365},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 5, want: 365},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 7, want: 511},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 7, want: 511},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 9, want: 657},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 9, want: 657},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 10, want: 730},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 10, want: 730},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 11, want: 803},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 11, want: 803},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 13, want: 949},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 13, want: 949},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 19, want: 1387},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 19, want: 1387},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 21, want: 1533},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 21, want: 1533},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 25, want: 1825},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 25, want: 1825},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 27, want: 1971},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 27, want: 1971},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 37, want: 2701},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 37, want: 2701},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 41, want: 2993},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 41, want: 2993},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 45, want: 3285},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 45, want: 3285},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 73, want: 5329},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 73, want: 5329},
+ test_uint32{fn: mul_73_uint32, fnname: "mul_73_uint32", in: 81, want: 5913},
+ test_uint32{fn: mul_uint32_73, fnname: "mul_uint32_73", in: 81, want: 5913},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 3, want: 243},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 3, want: 243},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 5, want: 405},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 5, want: 405},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 7, want: 567},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 7, want: 567},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 9, want: 729},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 9, want: 729},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 10, want: 810},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 10, want: 810},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 11, want: 891},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 11, want: 891},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 13, want: 1053},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 13, want: 1053},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 19, want: 1539},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 19, want: 1539},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 21, want: 1701},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 21, want: 1701},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 25, want: 2025},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 25, want: 2025},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 27, want: 2187},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 27, want: 2187},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 37, want: 2997},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 37, want: 2997},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 41, want: 3321},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 41, want: 3321},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 45, want: 3645},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 45, want: 3645},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 73, want: 5913},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 73, want: 5913},
+ test_uint32{fn: mul_81_uint32, fnname: "mul_81_uint32", in: 81, want: 6561},
+ test_uint32{fn: mul_uint32_81, fnname: "mul_uint32_81", in: 81, want: 6561}}
+
+type test_int32 struct {
+ fn func(int32) int32
+ fnname string
+ in int32
+ want int32
+}
+
+var tests_int32 = []test_int32{
+
+ test_int32{fn: add_Neg2147483648_int32, fnname: "add_Neg2147483648_int32", in: -2147483648, want: 0},
+ test_int32{fn: add_int32_Neg2147483648, fnname: "add_int32_Neg2147483648", in: -2147483648, want: 0},
+ test_int32{fn: add_Neg2147483648_int32, fnname: "add_Neg2147483648_int32", in: -2147483647, want: 1},
+ test_int32{fn: add_int32_Neg2147483648, fnname: "add_int32_Neg2147483648", in: -2147483647, want: 1},
+ test_int32{fn: add_Neg2147483648_int32, fnname: "add_Neg2147483648_int32", in: -1, want: 2147483647},
+ test_int32{fn: add_int32_Neg2147483648, fnname: "add_int32_Neg2147483648", in: -1, want: 2147483647},
+ test_int32{fn: add_Neg2147483648_int32, fnname: "add_Neg2147483648_int32", in: 0, want: -2147483648},
+ test_int32{fn: add_int32_Neg2147483648, fnname: "add_int32_Neg2147483648", in: 0, want: -2147483648},
+ test_int32{fn: add_Neg2147483648_int32, fnname: "add_Neg2147483648_int32", in: 1, want: -2147483647},
+ test_int32{fn: add_int32_Neg2147483648, fnname: "add_int32_Neg2147483648", in: 1, want: -2147483647},
+ test_int32{fn: add_Neg2147483648_int32, fnname: "add_Neg2147483648_int32", in: 2147483647, want: -1},
+ test_int32{fn: add_int32_Neg2147483648, fnname: "add_int32_Neg2147483648", in: 2147483647, want: -1},
+ test_int32{fn: add_Neg2147483647_int32, fnname: "add_Neg2147483647_int32", in: -2147483648, want: 1},
+ test_int32{fn: add_int32_Neg2147483647, fnname: "add_int32_Neg2147483647", in: -2147483648, want: 1},
+ test_int32{fn: add_Neg2147483647_int32, fnname: "add_Neg2147483647_int32", in: -2147483647, want: 2},
+ test_int32{fn: add_int32_Neg2147483647, fnname: "add_int32_Neg2147483647", in: -2147483647, want: 2},
+ test_int32{fn: add_Neg2147483647_int32, fnname: "add_Neg2147483647_int32", in: -1, want: -2147483648},
+ test_int32{fn: add_int32_Neg2147483647, fnname: "add_int32_Neg2147483647", in: -1, want: -2147483648},
+ test_int32{fn: add_Neg2147483647_int32, fnname: "add_Neg2147483647_int32", in: 0, want: -2147483647},
+ test_int32{fn: add_int32_Neg2147483647, fnname: "add_int32_Neg2147483647", in: 0, want: -2147483647},
+ test_int32{fn: add_Neg2147483647_int32, fnname: "add_Neg2147483647_int32", in: 1, want: -2147483646},
+ test_int32{fn: add_int32_Neg2147483647, fnname: "add_int32_Neg2147483647", in: 1, want: -2147483646},
+ test_int32{fn: add_Neg2147483647_int32, fnname: "add_Neg2147483647_int32", in: 2147483647, want: 0},
+ test_int32{fn: add_int32_Neg2147483647, fnname: "add_int32_Neg2147483647", in: 2147483647, want: 0},
+ test_int32{fn: add_Neg1_int32, fnname: "add_Neg1_int32", in: -2147483648, want: 2147483647},
+ test_int32{fn: add_int32_Neg1, fnname: "add_int32_Neg1", in: -2147483648, want: 2147483647},
+ test_int32{fn: add_Neg1_int32, fnname: "add_Neg1_int32", in: -2147483647, want: -2147483648},
+ test_int32{fn: add_int32_Neg1, fnname: "add_int32_Neg1", in: -2147483647, want: -2147483648},
+ test_int32{fn: add_Neg1_int32, fnname: "add_Neg1_int32", in: -1, want: -2},
+ test_int32{fn: add_int32_Neg1, fnname: "add_int32_Neg1", in: -1, want: -2},
+ test_int32{fn: add_Neg1_int32, fnname: "add_Neg1_int32", in: 0, want: -1},
+ test_int32{fn: add_int32_Neg1, fnname: "add_int32_Neg1", in: 0, want: -1},
+ test_int32{fn: add_Neg1_int32, fnname: "add_Neg1_int32", in: 1, want: 0},
+ test_int32{fn: add_int32_Neg1, fnname: "add_int32_Neg1", in: 1, want: 0},
+ test_int32{fn: add_Neg1_int32, fnname: "add_Neg1_int32", in: 2147483647, want: 2147483646},
+ test_int32{fn: add_int32_Neg1, fnname: "add_int32_Neg1", in: 2147483647, want: 2147483646},
+ test_int32{fn: add_0_int32, fnname: "add_0_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: add_int32_0, fnname: "add_int32_0", in: -2147483648, want: -2147483648},
+ test_int32{fn: add_0_int32, fnname: "add_0_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: add_int32_0, fnname: "add_int32_0", in: -2147483647, want: -2147483647},
+ test_int32{fn: add_0_int32, fnname: "add_0_int32", in: -1, want: -1},
+ test_int32{fn: add_int32_0, fnname: "add_int32_0", in: -1, want: -1},
+ test_int32{fn: add_0_int32, fnname: "add_0_int32", in: 0, want: 0},
+ test_int32{fn: add_int32_0, fnname: "add_int32_0", in: 0, want: 0},
+ test_int32{fn: add_0_int32, fnname: "add_0_int32", in: 1, want: 1},
+ test_int32{fn: add_int32_0, fnname: "add_int32_0", in: 1, want: 1},
+ test_int32{fn: add_0_int32, fnname: "add_0_int32", in: 2147483647, want: 2147483647},
+ test_int32{fn: add_int32_0, fnname: "add_int32_0", in: 2147483647, want: 2147483647},
+ test_int32{fn: add_1_int32, fnname: "add_1_int32", in: -2147483648, want: -2147483647},
+ test_int32{fn: add_int32_1, fnname: "add_int32_1", in: -2147483648, want: -2147483647},
+ test_int32{fn: add_1_int32, fnname: "add_1_int32", in: -2147483647, want: -2147483646},
+ test_int32{fn: add_int32_1, fnname: "add_int32_1", in: -2147483647, want: -2147483646},
+ test_int32{fn: add_1_int32, fnname: "add_1_int32", in: -1, want: 0},
+ test_int32{fn: add_int32_1, fnname: "add_int32_1", in: -1, want: 0},
+ test_int32{fn: add_1_int32, fnname: "add_1_int32", in: 0, want: 1},
+ test_int32{fn: add_int32_1, fnname: "add_int32_1", in: 0, want: 1},
+ test_int32{fn: add_1_int32, fnname: "add_1_int32", in: 1, want: 2},
+ test_int32{fn: add_int32_1, fnname: "add_int32_1", in: 1, want: 2},
+ test_int32{fn: add_1_int32, fnname: "add_1_int32", in: 2147483647, want: -2147483648},
+ test_int32{fn: add_int32_1, fnname: "add_int32_1", in: 2147483647, want: -2147483648},
+ test_int32{fn: add_2147483647_int32, fnname: "add_2147483647_int32", in: -2147483648, want: -1},
+ test_int32{fn: add_int32_2147483647, fnname: "add_int32_2147483647", in: -2147483648, want: -1},
+ test_int32{fn: add_2147483647_int32, fnname: "add_2147483647_int32", in: -2147483647, want: 0},
+ test_int32{fn: add_int32_2147483647, fnname: "add_int32_2147483647", in: -2147483647, want: 0},
+ test_int32{fn: add_2147483647_int32, fnname: "add_2147483647_int32", in: -1, want: 2147483646},
+ test_int32{fn: add_int32_2147483647, fnname: "add_int32_2147483647", in: -1, want: 2147483646},
+ test_int32{fn: add_2147483647_int32, fnname: "add_2147483647_int32", in: 0, want: 2147483647},
+ test_int32{fn: add_int32_2147483647, fnname: "add_int32_2147483647", in: 0, want: 2147483647},
+ test_int32{fn: add_2147483647_int32, fnname: "add_2147483647_int32", in: 1, want: -2147483648},
+ test_int32{fn: add_int32_2147483647, fnname: "add_int32_2147483647", in: 1, want: -2147483648},
+ test_int32{fn: add_2147483647_int32, fnname: "add_2147483647_int32", in: 2147483647, want: -2},
+ test_int32{fn: add_int32_2147483647, fnname: "add_int32_2147483647", in: 2147483647, want: -2},
+ test_int32{fn: sub_Neg2147483648_int32, fnname: "sub_Neg2147483648_int32", in: -2147483648, want: 0},
+ test_int32{fn: sub_int32_Neg2147483648, fnname: "sub_int32_Neg2147483648", in: -2147483648, want: 0},
+ test_int32{fn: sub_Neg2147483648_int32, fnname: "sub_Neg2147483648_int32", in: -2147483647, want: -1},
+ test_int32{fn: sub_int32_Neg2147483648, fnname: "sub_int32_Neg2147483648", in: -2147483647, want: 1},
+ test_int32{fn: sub_Neg2147483648_int32, fnname: "sub_Neg2147483648_int32", in: -1, want: -2147483647},
+ test_int32{fn: sub_int32_Neg2147483648, fnname: "sub_int32_Neg2147483648", in: -1, want: 2147483647},
+ test_int32{fn: sub_Neg2147483648_int32, fnname: "sub_Neg2147483648_int32", in: 0, want: -2147483648},
+ test_int32{fn: sub_int32_Neg2147483648, fnname: "sub_int32_Neg2147483648", in: 0, want: -2147483648},
+ test_int32{fn: sub_Neg2147483648_int32, fnname: "sub_Neg2147483648_int32", in: 1, want: 2147483647},
+ test_int32{fn: sub_int32_Neg2147483648, fnname: "sub_int32_Neg2147483648", in: 1, want: -2147483647},
+ test_int32{fn: sub_Neg2147483648_int32, fnname: "sub_Neg2147483648_int32", in: 2147483647, want: 1},
+ test_int32{fn: sub_int32_Neg2147483648, fnname: "sub_int32_Neg2147483648", in: 2147483647, want: -1},
+ test_int32{fn: sub_Neg2147483647_int32, fnname: "sub_Neg2147483647_int32", in: -2147483648, want: 1},
+ test_int32{fn: sub_int32_Neg2147483647, fnname: "sub_int32_Neg2147483647", in: -2147483648, want: -1},
+ test_int32{fn: sub_Neg2147483647_int32, fnname: "sub_Neg2147483647_int32", in: -2147483647, want: 0},
+ test_int32{fn: sub_int32_Neg2147483647, fnname: "sub_int32_Neg2147483647", in: -2147483647, want: 0},
+ test_int32{fn: sub_Neg2147483647_int32, fnname: "sub_Neg2147483647_int32", in: -1, want: -2147483646},
+ test_int32{fn: sub_int32_Neg2147483647, fnname: "sub_int32_Neg2147483647", in: -1, want: 2147483646},
+ test_int32{fn: sub_Neg2147483647_int32, fnname: "sub_Neg2147483647_int32", in: 0, want: -2147483647},
+ test_int32{fn: sub_int32_Neg2147483647, fnname: "sub_int32_Neg2147483647", in: 0, want: 2147483647},
+ test_int32{fn: sub_Neg2147483647_int32, fnname: "sub_Neg2147483647_int32", in: 1, want: -2147483648},
+ test_int32{fn: sub_int32_Neg2147483647, fnname: "sub_int32_Neg2147483647", in: 1, want: -2147483648},
+ test_int32{fn: sub_Neg2147483647_int32, fnname: "sub_Neg2147483647_int32", in: 2147483647, want: 2},
+ test_int32{fn: sub_int32_Neg2147483647, fnname: "sub_int32_Neg2147483647", in: 2147483647, want: -2},
+ test_int32{fn: sub_Neg1_int32, fnname: "sub_Neg1_int32", in: -2147483648, want: 2147483647},
+ test_int32{fn: sub_int32_Neg1, fnname: "sub_int32_Neg1", in: -2147483648, want: -2147483647},
+ test_int32{fn: sub_Neg1_int32, fnname: "sub_Neg1_int32", in: -2147483647, want: 2147483646},
+ test_int32{fn: sub_int32_Neg1, fnname: "sub_int32_Neg1", in: -2147483647, want: -2147483646},
+ test_int32{fn: sub_Neg1_int32, fnname: "sub_Neg1_int32", in: -1, want: 0},
+ test_int32{fn: sub_int32_Neg1, fnname: "sub_int32_Neg1", in: -1, want: 0},
+ test_int32{fn: sub_Neg1_int32, fnname: "sub_Neg1_int32", in: 0, want: -1},
+ test_int32{fn: sub_int32_Neg1, fnname: "sub_int32_Neg1", in: 0, want: 1},
+ test_int32{fn: sub_Neg1_int32, fnname: "sub_Neg1_int32", in: 1, want: -2},
+ test_int32{fn: sub_int32_Neg1, fnname: "sub_int32_Neg1", in: 1, want: 2},
+ test_int32{fn: sub_Neg1_int32, fnname: "sub_Neg1_int32", in: 2147483647, want: -2147483648},
+ test_int32{fn: sub_int32_Neg1, fnname: "sub_int32_Neg1", in: 2147483647, want: -2147483648},
+ test_int32{fn: sub_0_int32, fnname: "sub_0_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: sub_int32_0, fnname: "sub_int32_0", in: -2147483648, want: -2147483648},
+ test_int32{fn: sub_0_int32, fnname: "sub_0_int32", in: -2147483647, want: 2147483647},
+ test_int32{fn: sub_int32_0, fnname: "sub_int32_0", in: -2147483647, want: -2147483647},
+ test_int32{fn: sub_0_int32, fnname: "sub_0_int32", in: -1, want: 1},
+ test_int32{fn: sub_int32_0, fnname: "sub_int32_0", in: -1, want: -1},
+ test_int32{fn: sub_0_int32, fnname: "sub_0_int32", in: 0, want: 0},
+ test_int32{fn: sub_int32_0, fnname: "sub_int32_0", in: 0, want: 0},
+ test_int32{fn: sub_0_int32, fnname: "sub_0_int32", in: 1, want: -1},
+ test_int32{fn: sub_int32_0, fnname: "sub_int32_0", in: 1, want: 1},
+ test_int32{fn: sub_0_int32, fnname: "sub_0_int32", in: 2147483647, want: -2147483647},
+ test_int32{fn: sub_int32_0, fnname: "sub_int32_0", in: 2147483647, want: 2147483647},
+ test_int32{fn: sub_1_int32, fnname: "sub_1_int32", in: -2147483648, want: -2147483647},
+ test_int32{fn: sub_int32_1, fnname: "sub_int32_1", in: -2147483648, want: 2147483647},
+ test_int32{fn: sub_1_int32, fnname: "sub_1_int32", in: -2147483647, want: -2147483648},
+ test_int32{fn: sub_int32_1, fnname: "sub_int32_1", in: -2147483647, want: -2147483648},
+ test_int32{fn: sub_1_int32, fnname: "sub_1_int32", in: -1, want: 2},
+ test_int32{fn: sub_int32_1, fnname: "sub_int32_1", in: -1, want: -2},
+ test_int32{fn: sub_1_int32, fnname: "sub_1_int32", in: 0, want: 1},
+ test_int32{fn: sub_int32_1, fnname: "sub_int32_1", in: 0, want: -1},
+ test_int32{fn: sub_1_int32, fnname: "sub_1_int32", in: 1, want: 0},
+ test_int32{fn: sub_int32_1, fnname: "sub_int32_1", in: 1, want: 0},
+ test_int32{fn: sub_1_int32, fnname: "sub_1_int32", in: 2147483647, want: -2147483646},
+ test_int32{fn: sub_int32_1, fnname: "sub_int32_1", in: 2147483647, want: 2147483646},
+ test_int32{fn: sub_2147483647_int32, fnname: "sub_2147483647_int32", in: -2147483648, want: -1},
+ test_int32{fn: sub_int32_2147483647, fnname: "sub_int32_2147483647", in: -2147483648, want: 1},
+ test_int32{fn: sub_2147483647_int32, fnname: "sub_2147483647_int32", in: -2147483647, want: -2},
+ test_int32{fn: sub_int32_2147483647, fnname: "sub_int32_2147483647", in: -2147483647, want: 2},
+ test_int32{fn: sub_2147483647_int32, fnname: "sub_2147483647_int32", in: -1, want: -2147483648},
+ test_int32{fn: sub_int32_2147483647, fnname: "sub_int32_2147483647", in: -1, want: -2147483648},
+ test_int32{fn: sub_2147483647_int32, fnname: "sub_2147483647_int32", in: 0, want: 2147483647},
+ test_int32{fn: sub_int32_2147483647, fnname: "sub_int32_2147483647", in: 0, want: -2147483647},
+ test_int32{fn: sub_2147483647_int32, fnname: "sub_2147483647_int32", in: 1, want: 2147483646},
+ test_int32{fn: sub_int32_2147483647, fnname: "sub_int32_2147483647", in: 1, want: -2147483646},
+ test_int32{fn: sub_2147483647_int32, fnname: "sub_2147483647_int32", in: 2147483647, want: 0},
+ test_int32{fn: sub_int32_2147483647, fnname: "sub_int32_2147483647", in: 2147483647, want: 0},
+ test_int32{fn: div_Neg2147483648_int32, fnname: "div_Neg2147483648_int32", in: -2147483648, want: 1},
+ test_int32{fn: div_int32_Neg2147483648, fnname: "div_int32_Neg2147483648", in: -2147483648, want: 1},
+ test_int32{fn: div_Neg2147483648_int32, fnname: "div_Neg2147483648_int32", in: -2147483647, want: 1},
+ test_int32{fn: div_int32_Neg2147483648, fnname: "div_int32_Neg2147483648", in: -2147483647, want: 0},
+ test_int32{fn: div_Neg2147483648_int32, fnname: "div_Neg2147483648_int32", in: -1, want: -2147483648},
+ test_int32{fn: div_int32_Neg2147483648, fnname: "div_int32_Neg2147483648", in: -1, want: 0},
+ test_int32{fn: div_int32_Neg2147483648, fnname: "div_int32_Neg2147483648", in: 0, want: 0},
+ test_int32{fn: div_Neg2147483648_int32, fnname: "div_Neg2147483648_int32", in: 1, want: -2147483648},
+ test_int32{fn: div_int32_Neg2147483648, fnname: "div_int32_Neg2147483648", in: 1, want: 0},
+ test_int32{fn: div_Neg2147483648_int32, fnname: "div_Neg2147483648_int32", in: 2147483647, want: -1},
+ test_int32{fn: div_int32_Neg2147483648, fnname: "div_int32_Neg2147483648", in: 2147483647, want: 0},
+ test_int32{fn: div_Neg2147483647_int32, fnname: "div_Neg2147483647_int32", in: -2147483648, want: 0},
+ test_int32{fn: div_int32_Neg2147483647, fnname: "div_int32_Neg2147483647", in: -2147483648, want: 1},
+ test_int32{fn: div_Neg2147483647_int32, fnname: "div_Neg2147483647_int32", in: -2147483647, want: 1},
+ test_int32{fn: div_int32_Neg2147483647, fnname: "div_int32_Neg2147483647", in: -2147483647, want: 1},
+ test_int32{fn: div_Neg2147483647_int32, fnname: "div_Neg2147483647_int32", in: -1, want: 2147483647},
+ test_int32{fn: div_int32_Neg2147483647, fnname: "div_int32_Neg2147483647", in: -1, want: 0},
+ test_int32{fn: div_int32_Neg2147483647, fnname: "div_int32_Neg2147483647", in: 0, want: 0},
+ test_int32{fn: div_Neg2147483647_int32, fnname: "div_Neg2147483647_int32", in: 1, want: -2147483647},
+ test_int32{fn: div_int32_Neg2147483647, fnname: "div_int32_Neg2147483647", in: 1, want: 0},
+ test_int32{fn: div_Neg2147483647_int32, fnname: "div_Neg2147483647_int32", in: 2147483647, want: -1},
+ test_int32{fn: div_int32_Neg2147483647, fnname: "div_int32_Neg2147483647", in: 2147483647, want: -1},
+ test_int32{fn: div_Neg1_int32, fnname: "div_Neg1_int32", in: -2147483648, want: 0},
+ test_int32{fn: div_int32_Neg1, fnname: "div_int32_Neg1", in: -2147483648, want: -2147483648},
+ test_int32{fn: div_Neg1_int32, fnname: "div_Neg1_int32", in: -2147483647, want: 0},
+ test_int32{fn: div_int32_Neg1, fnname: "div_int32_Neg1", in: -2147483647, want: 2147483647},
+ test_int32{fn: div_Neg1_int32, fnname: "div_Neg1_int32", in: -1, want: 1},
+ test_int32{fn: div_int32_Neg1, fnname: "div_int32_Neg1", in: -1, want: 1},
+ test_int32{fn: div_int32_Neg1, fnname: "div_int32_Neg1", in: 0, want: 0},
+ test_int32{fn: div_Neg1_int32, fnname: "div_Neg1_int32", in: 1, want: -1},
+ test_int32{fn: div_int32_Neg1, fnname: "div_int32_Neg1", in: 1, want: -1},
+ test_int32{fn: div_Neg1_int32, fnname: "div_Neg1_int32", in: 2147483647, want: 0},
+ test_int32{fn: div_int32_Neg1, fnname: "div_int32_Neg1", in: 2147483647, want: -2147483647},
+ test_int32{fn: div_0_int32, fnname: "div_0_int32", in: -2147483648, want: 0},
+ test_int32{fn: div_0_int32, fnname: "div_0_int32", in: -2147483647, want: 0},
+ test_int32{fn: div_0_int32, fnname: "div_0_int32", in: -1, want: 0},
+ test_int32{fn: div_0_int32, fnname: "div_0_int32", in: 1, want: 0},
+ test_int32{fn: div_0_int32, fnname: "div_0_int32", in: 2147483647, want: 0},
+ test_int32{fn: div_1_int32, fnname: "div_1_int32", in: -2147483648, want: 0},
+ test_int32{fn: div_int32_1, fnname: "div_int32_1", in: -2147483648, want: -2147483648},
+ test_int32{fn: div_1_int32, fnname: "div_1_int32", in: -2147483647, want: 0},
+ test_int32{fn: div_int32_1, fnname: "div_int32_1", in: -2147483647, want: -2147483647},
+ test_int32{fn: div_1_int32, fnname: "div_1_int32", in: -1, want: -1},
+ test_int32{fn: div_int32_1, fnname: "div_int32_1", in: -1, want: -1},
+ test_int32{fn: div_int32_1, fnname: "div_int32_1", in: 0, want: 0},
+ test_int32{fn: div_1_int32, fnname: "div_1_int32", in: 1, want: 1},
+ test_int32{fn: div_int32_1, fnname: "div_int32_1", in: 1, want: 1},
+ test_int32{fn: div_1_int32, fnname: "div_1_int32", in: 2147483647, want: 0},
+ test_int32{fn: div_int32_1, fnname: "div_int32_1", in: 2147483647, want: 2147483647},
+ test_int32{fn: div_2147483647_int32, fnname: "div_2147483647_int32", in: -2147483648, want: 0},
+ test_int32{fn: div_int32_2147483647, fnname: "div_int32_2147483647", in: -2147483648, want: -1},
+ test_int32{fn: div_2147483647_int32, fnname: "div_2147483647_int32", in: -2147483647, want: -1},
+ test_int32{fn: div_int32_2147483647, fnname: "div_int32_2147483647", in: -2147483647, want: -1},
+ test_int32{fn: div_2147483647_int32, fnname: "div_2147483647_int32", in: -1, want: -2147483647},
+ test_int32{fn: div_int32_2147483647, fnname: "div_int32_2147483647", in: -1, want: 0},
+ test_int32{fn: div_int32_2147483647, fnname: "div_int32_2147483647", in: 0, want: 0},
+ test_int32{fn: div_2147483647_int32, fnname: "div_2147483647_int32", in: 1, want: 2147483647},
+ test_int32{fn: div_int32_2147483647, fnname: "div_int32_2147483647", in: 1, want: 0},
+ test_int32{fn: div_2147483647_int32, fnname: "div_2147483647_int32", in: 2147483647, want: 1},
+ test_int32{fn: div_int32_2147483647, fnname: "div_int32_2147483647", in: 2147483647, want: 1},
+ test_int32{fn: mul_Neg2147483648_int32, fnname: "mul_Neg2147483648_int32", in: -2147483648, want: 0},
+ test_int32{fn: mul_int32_Neg2147483648, fnname: "mul_int32_Neg2147483648", in: -2147483648, want: 0},
+ test_int32{fn: mul_Neg2147483648_int32, fnname: "mul_Neg2147483648_int32", in: -2147483647, want: -2147483648},
+ test_int32{fn: mul_int32_Neg2147483648, fnname: "mul_int32_Neg2147483648", in: -2147483647, want: -2147483648},
+ test_int32{fn: mul_Neg2147483648_int32, fnname: "mul_Neg2147483648_int32", in: -1, want: -2147483648},
+ test_int32{fn: mul_int32_Neg2147483648, fnname: "mul_int32_Neg2147483648", in: -1, want: -2147483648},
+ test_int32{fn: mul_Neg2147483648_int32, fnname: "mul_Neg2147483648_int32", in: 0, want: 0},
+ test_int32{fn: mul_int32_Neg2147483648, fnname: "mul_int32_Neg2147483648", in: 0, want: 0},
+ test_int32{fn: mul_Neg2147483648_int32, fnname: "mul_Neg2147483648_int32", in: 1, want: -2147483648},
+ test_int32{fn: mul_int32_Neg2147483648, fnname: "mul_int32_Neg2147483648", in: 1, want: -2147483648},
+ test_int32{fn: mul_Neg2147483648_int32, fnname: "mul_Neg2147483648_int32", in: 2147483647, want: -2147483648},
+ test_int32{fn: mul_int32_Neg2147483648, fnname: "mul_int32_Neg2147483648", in: 2147483647, want: -2147483648},
+ test_int32{fn: mul_Neg2147483647_int32, fnname: "mul_Neg2147483647_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: mul_int32_Neg2147483647, fnname: "mul_int32_Neg2147483647", in: -2147483648, want: -2147483648},
+ test_int32{fn: mul_Neg2147483647_int32, fnname: "mul_Neg2147483647_int32", in: -2147483647, want: 1},
+ test_int32{fn: mul_int32_Neg2147483647, fnname: "mul_int32_Neg2147483647", in: -2147483647, want: 1},
+ test_int32{fn: mul_Neg2147483647_int32, fnname: "mul_Neg2147483647_int32", in: -1, want: 2147483647},
+ test_int32{fn: mul_int32_Neg2147483647, fnname: "mul_int32_Neg2147483647", in: -1, want: 2147483647},
+ test_int32{fn: mul_Neg2147483647_int32, fnname: "mul_Neg2147483647_int32", in: 0, want: 0},
+ test_int32{fn: mul_int32_Neg2147483647, fnname: "mul_int32_Neg2147483647", in: 0, want: 0},
+ test_int32{fn: mul_Neg2147483647_int32, fnname: "mul_Neg2147483647_int32", in: 1, want: -2147483647},
+ test_int32{fn: mul_int32_Neg2147483647, fnname: "mul_int32_Neg2147483647", in: 1, want: -2147483647},
+ test_int32{fn: mul_Neg2147483647_int32, fnname: "mul_Neg2147483647_int32", in: 2147483647, want: -1},
+ test_int32{fn: mul_int32_Neg2147483647, fnname: "mul_int32_Neg2147483647", in: 2147483647, want: -1},
+ test_int32{fn: mul_Neg1_int32, fnname: "mul_Neg1_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: mul_int32_Neg1, fnname: "mul_int32_Neg1", in: -2147483648, want: -2147483648},
+ test_int32{fn: mul_Neg1_int32, fnname: "mul_Neg1_int32", in: -2147483647, want: 2147483647},
+ test_int32{fn: mul_int32_Neg1, fnname: "mul_int32_Neg1", in: -2147483647, want: 2147483647},
+ test_int32{fn: mul_Neg1_int32, fnname: "mul_Neg1_int32", in: -1, want: 1},
+ test_int32{fn: mul_int32_Neg1, fnname: "mul_int32_Neg1", in: -1, want: 1},
+ test_int32{fn: mul_Neg1_int32, fnname: "mul_Neg1_int32", in: 0, want: 0},
+ test_int32{fn: mul_int32_Neg1, fnname: "mul_int32_Neg1", in: 0, want: 0},
+ test_int32{fn: mul_Neg1_int32, fnname: "mul_Neg1_int32", in: 1, want: -1},
+ test_int32{fn: mul_int32_Neg1, fnname: "mul_int32_Neg1", in: 1, want: -1},
+ test_int32{fn: mul_Neg1_int32, fnname: "mul_Neg1_int32", in: 2147483647, want: -2147483647},
+ test_int32{fn: mul_int32_Neg1, fnname: "mul_int32_Neg1", in: 2147483647, want: -2147483647},
+ test_int32{fn: mul_0_int32, fnname: "mul_0_int32", in: -2147483648, want: 0},
+ test_int32{fn: mul_int32_0, fnname: "mul_int32_0", in: -2147483648, want: 0},
+ test_int32{fn: mul_0_int32, fnname: "mul_0_int32", in: -2147483647, want: 0},
+ test_int32{fn: mul_int32_0, fnname: "mul_int32_0", in: -2147483647, want: 0},
+ test_int32{fn: mul_0_int32, fnname: "mul_0_int32", in: -1, want: 0},
+ test_int32{fn: mul_int32_0, fnname: "mul_int32_0", in: -1, want: 0},
+ test_int32{fn: mul_0_int32, fnname: "mul_0_int32", in: 0, want: 0},
+ test_int32{fn: mul_int32_0, fnname: "mul_int32_0", in: 0, want: 0},
+ test_int32{fn: mul_0_int32, fnname: "mul_0_int32", in: 1, want: 0},
+ test_int32{fn: mul_int32_0, fnname: "mul_int32_0", in: 1, want: 0},
+ test_int32{fn: mul_0_int32, fnname: "mul_0_int32", in: 2147483647, want: 0},
+ test_int32{fn: mul_int32_0, fnname: "mul_int32_0", in: 2147483647, want: 0},
+ test_int32{fn: mul_1_int32, fnname: "mul_1_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: mul_int32_1, fnname: "mul_int32_1", in: -2147483648, want: -2147483648},
+ test_int32{fn: mul_1_int32, fnname: "mul_1_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: mul_int32_1, fnname: "mul_int32_1", in: -2147483647, want: -2147483647},
+ test_int32{fn: mul_1_int32, fnname: "mul_1_int32", in: -1, want: -1},
+ test_int32{fn: mul_int32_1, fnname: "mul_int32_1", in: -1, want: -1},
+ test_int32{fn: mul_1_int32, fnname: "mul_1_int32", in: 0, want: 0},
+ test_int32{fn: mul_int32_1, fnname: "mul_int32_1", in: 0, want: 0},
+ test_int32{fn: mul_1_int32, fnname: "mul_1_int32", in: 1, want: 1},
+ test_int32{fn: mul_int32_1, fnname: "mul_int32_1", in: 1, want: 1},
+ test_int32{fn: mul_1_int32, fnname: "mul_1_int32", in: 2147483647, want: 2147483647},
+ test_int32{fn: mul_int32_1, fnname: "mul_int32_1", in: 2147483647, want: 2147483647},
+ test_int32{fn: mul_2147483647_int32, fnname: "mul_2147483647_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: mul_int32_2147483647, fnname: "mul_int32_2147483647", in: -2147483648, want: -2147483648},
+ test_int32{fn: mul_2147483647_int32, fnname: "mul_2147483647_int32", in: -2147483647, want: -1},
+ test_int32{fn: mul_int32_2147483647, fnname: "mul_int32_2147483647", in: -2147483647, want: -1},
+ test_int32{fn: mul_2147483647_int32, fnname: "mul_2147483647_int32", in: -1, want: -2147483647},
+ test_int32{fn: mul_int32_2147483647, fnname: "mul_int32_2147483647", in: -1, want: -2147483647},
+ test_int32{fn: mul_2147483647_int32, fnname: "mul_2147483647_int32", in: 0, want: 0},
+ test_int32{fn: mul_int32_2147483647, fnname: "mul_int32_2147483647", in: 0, want: 0},
+ test_int32{fn: mul_2147483647_int32, fnname: "mul_2147483647_int32", in: 1, want: 2147483647},
+ test_int32{fn: mul_int32_2147483647, fnname: "mul_int32_2147483647", in: 1, want: 2147483647},
+ test_int32{fn: mul_2147483647_int32, fnname: "mul_2147483647_int32", in: 2147483647, want: 1},
+ test_int32{fn: mul_int32_2147483647, fnname: "mul_int32_2147483647", in: 2147483647, want: 1},
+ test_int32{fn: mod_Neg2147483648_int32, fnname: "mod_Neg2147483648_int32", in: -2147483648, want: 0},
+ test_int32{fn: mod_int32_Neg2147483648, fnname: "mod_int32_Neg2147483648", in: -2147483648, want: 0},
+ test_int32{fn: mod_Neg2147483648_int32, fnname: "mod_Neg2147483648_int32", in: -2147483647, want: -1},
+ test_int32{fn: mod_int32_Neg2147483648, fnname: "mod_int32_Neg2147483648", in: -2147483647, want: -2147483647},
+ test_int32{fn: mod_Neg2147483648_int32, fnname: "mod_Neg2147483648_int32", in: -1, want: 0},
+ test_int32{fn: mod_int32_Neg2147483648, fnname: "mod_int32_Neg2147483648", in: -1, want: -1},
+ test_int32{fn: mod_int32_Neg2147483648, fnname: "mod_int32_Neg2147483648", in: 0, want: 0},
+ test_int32{fn: mod_Neg2147483648_int32, fnname: "mod_Neg2147483648_int32", in: 1, want: 0},
+ test_int32{fn: mod_int32_Neg2147483648, fnname: "mod_int32_Neg2147483648", in: 1, want: 1},
+ test_int32{fn: mod_Neg2147483648_int32, fnname: "mod_Neg2147483648_int32", in: 2147483647, want: -1},
+ test_int32{fn: mod_int32_Neg2147483648, fnname: "mod_int32_Neg2147483648", in: 2147483647, want: 2147483647},
+ test_int32{fn: mod_Neg2147483647_int32, fnname: "mod_Neg2147483647_int32", in: -2147483648, want: -2147483647},
+ test_int32{fn: mod_int32_Neg2147483647, fnname: "mod_int32_Neg2147483647", in: -2147483648, want: -1},
+ test_int32{fn: mod_Neg2147483647_int32, fnname: "mod_Neg2147483647_int32", in: -2147483647, want: 0},
+ test_int32{fn: mod_int32_Neg2147483647, fnname: "mod_int32_Neg2147483647", in: -2147483647, want: 0},
+ test_int32{fn: mod_Neg2147483647_int32, fnname: "mod_Neg2147483647_int32", in: -1, want: 0},
+ test_int32{fn: mod_int32_Neg2147483647, fnname: "mod_int32_Neg2147483647", in: -1, want: -1},
+ test_int32{fn: mod_int32_Neg2147483647, fnname: "mod_int32_Neg2147483647", in: 0, want: 0},
+ test_int32{fn: mod_Neg2147483647_int32, fnname: "mod_Neg2147483647_int32", in: 1, want: 0},
+ test_int32{fn: mod_int32_Neg2147483647, fnname: "mod_int32_Neg2147483647", in: 1, want: 1},
+ test_int32{fn: mod_Neg2147483647_int32, fnname: "mod_Neg2147483647_int32", in: 2147483647, want: 0},
+ test_int32{fn: mod_int32_Neg2147483647, fnname: "mod_int32_Neg2147483647", in: 2147483647, want: 0},
+ test_int32{fn: mod_Neg1_int32, fnname: "mod_Neg1_int32", in: -2147483648, want: -1},
+ test_int32{fn: mod_int32_Neg1, fnname: "mod_int32_Neg1", in: -2147483648, want: 0},
+ test_int32{fn: mod_Neg1_int32, fnname: "mod_Neg1_int32", in: -2147483647, want: -1},
+ test_int32{fn: mod_int32_Neg1, fnname: "mod_int32_Neg1", in: -2147483647, want: 0},
+ test_int32{fn: mod_Neg1_int32, fnname: "mod_Neg1_int32", in: -1, want: 0},
+ test_int32{fn: mod_int32_Neg1, fnname: "mod_int32_Neg1", in: -1, want: 0},
+ test_int32{fn: mod_int32_Neg1, fnname: "mod_int32_Neg1", in: 0, want: 0},
+ test_int32{fn: mod_Neg1_int32, fnname: "mod_Neg1_int32", in: 1, want: 0},
+ test_int32{fn: mod_int32_Neg1, fnname: "mod_int32_Neg1", in: 1, want: 0},
+ test_int32{fn: mod_Neg1_int32, fnname: "mod_Neg1_int32", in: 2147483647, want: -1},
+ test_int32{fn: mod_int32_Neg1, fnname: "mod_int32_Neg1", in: 2147483647, want: 0},
+ test_int32{fn: mod_0_int32, fnname: "mod_0_int32", in: -2147483648, want: 0},
+ test_int32{fn: mod_0_int32, fnname: "mod_0_int32", in: -2147483647, want: 0},
+ test_int32{fn: mod_0_int32, fnname: "mod_0_int32", in: -1, want: 0},
+ test_int32{fn: mod_0_int32, fnname: "mod_0_int32", in: 1, want: 0},
+ test_int32{fn: mod_0_int32, fnname: "mod_0_int32", in: 2147483647, want: 0},
+ test_int32{fn: mod_1_int32, fnname: "mod_1_int32", in: -2147483648, want: 1},
+ test_int32{fn: mod_int32_1, fnname: "mod_int32_1", in: -2147483648, want: 0},
+ test_int32{fn: mod_1_int32, fnname: "mod_1_int32", in: -2147483647, want: 1},
+ test_int32{fn: mod_int32_1, fnname: "mod_int32_1", in: -2147483647, want: 0},
+ test_int32{fn: mod_1_int32, fnname: "mod_1_int32", in: -1, want: 0},
+ test_int32{fn: mod_int32_1, fnname: "mod_int32_1", in: -1, want: 0},
+ test_int32{fn: mod_int32_1, fnname: "mod_int32_1", in: 0, want: 0},
+ test_int32{fn: mod_1_int32, fnname: "mod_1_int32", in: 1, want: 0},
+ test_int32{fn: mod_int32_1, fnname: "mod_int32_1", in: 1, want: 0},
+ test_int32{fn: mod_1_int32, fnname: "mod_1_int32", in: 2147483647, want: 1},
+ test_int32{fn: mod_int32_1, fnname: "mod_int32_1", in: 2147483647, want: 0},
+ test_int32{fn: mod_2147483647_int32, fnname: "mod_2147483647_int32", in: -2147483648, want: 2147483647},
+ test_int32{fn: mod_int32_2147483647, fnname: "mod_int32_2147483647", in: -2147483648, want: -1},
+ test_int32{fn: mod_2147483647_int32, fnname: "mod_2147483647_int32", in: -2147483647, want: 0},
+ test_int32{fn: mod_int32_2147483647, fnname: "mod_int32_2147483647", in: -2147483647, want: 0},
+ test_int32{fn: mod_2147483647_int32, fnname: "mod_2147483647_int32", in: -1, want: 0},
+ test_int32{fn: mod_int32_2147483647, fnname: "mod_int32_2147483647", in: -1, want: -1},
+ test_int32{fn: mod_int32_2147483647, fnname: "mod_int32_2147483647", in: 0, want: 0},
+ test_int32{fn: mod_2147483647_int32, fnname: "mod_2147483647_int32", in: 1, want: 0},
+ test_int32{fn: mod_int32_2147483647, fnname: "mod_int32_2147483647", in: 1, want: 1},
+ test_int32{fn: mod_2147483647_int32, fnname: "mod_2147483647_int32", in: 2147483647, want: 0},
+ test_int32{fn: mod_int32_2147483647, fnname: "mod_int32_2147483647", in: 2147483647, want: 0},
+ test_int32{fn: and_Neg2147483648_int32, fnname: "and_Neg2147483648_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: and_int32_Neg2147483648, fnname: "and_int32_Neg2147483648", in: -2147483648, want: -2147483648},
+ test_int32{fn: and_Neg2147483648_int32, fnname: "and_Neg2147483648_int32", in: -2147483647, want: -2147483648},
+ test_int32{fn: and_int32_Neg2147483648, fnname: "and_int32_Neg2147483648", in: -2147483647, want: -2147483648},
+ test_int32{fn: and_Neg2147483648_int32, fnname: "and_Neg2147483648_int32", in: -1, want: -2147483648},
+ test_int32{fn: and_int32_Neg2147483648, fnname: "and_int32_Neg2147483648", in: -1, want: -2147483648},
+ test_int32{fn: and_Neg2147483648_int32, fnname: "and_Neg2147483648_int32", in: 0, want: 0},
+ test_int32{fn: and_int32_Neg2147483648, fnname: "and_int32_Neg2147483648", in: 0, want: 0},
+ test_int32{fn: and_Neg2147483648_int32, fnname: "and_Neg2147483648_int32", in: 1, want: 0},
+ test_int32{fn: and_int32_Neg2147483648, fnname: "and_int32_Neg2147483648", in: 1, want: 0},
+ test_int32{fn: and_Neg2147483648_int32, fnname: "and_Neg2147483648_int32", in: 2147483647, want: 0},
+ test_int32{fn: and_int32_Neg2147483648, fnname: "and_int32_Neg2147483648", in: 2147483647, want: 0},
+ test_int32{fn: and_Neg2147483647_int32, fnname: "and_Neg2147483647_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: and_int32_Neg2147483647, fnname: "and_int32_Neg2147483647", in: -2147483648, want: -2147483648},
+ test_int32{fn: and_Neg2147483647_int32, fnname: "and_Neg2147483647_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: and_int32_Neg2147483647, fnname: "and_int32_Neg2147483647", in: -2147483647, want: -2147483647},
+ test_int32{fn: and_Neg2147483647_int32, fnname: "and_Neg2147483647_int32", in: -1, want: -2147483647},
+ test_int32{fn: and_int32_Neg2147483647, fnname: "and_int32_Neg2147483647", in: -1, want: -2147483647},
+ test_int32{fn: and_Neg2147483647_int32, fnname: "and_Neg2147483647_int32", in: 0, want: 0},
+ test_int32{fn: and_int32_Neg2147483647, fnname: "and_int32_Neg2147483647", in: 0, want: 0},
+ test_int32{fn: and_Neg2147483647_int32, fnname: "and_Neg2147483647_int32", in: 1, want: 1},
+ test_int32{fn: and_int32_Neg2147483647, fnname: "and_int32_Neg2147483647", in: 1, want: 1},
+ test_int32{fn: and_Neg2147483647_int32, fnname: "and_Neg2147483647_int32", in: 2147483647, want: 1},
+ test_int32{fn: and_int32_Neg2147483647, fnname: "and_int32_Neg2147483647", in: 2147483647, want: 1},
+ test_int32{fn: and_Neg1_int32, fnname: "and_Neg1_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: and_int32_Neg1, fnname: "and_int32_Neg1", in: -2147483648, want: -2147483648},
+ test_int32{fn: and_Neg1_int32, fnname: "and_Neg1_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: and_int32_Neg1, fnname: "and_int32_Neg1", in: -2147483647, want: -2147483647},
+ test_int32{fn: and_Neg1_int32, fnname: "and_Neg1_int32", in: -1, want: -1},
+ test_int32{fn: and_int32_Neg1, fnname: "and_int32_Neg1", in: -1, want: -1},
+ test_int32{fn: and_Neg1_int32, fnname: "and_Neg1_int32", in: 0, want: 0},
+ test_int32{fn: and_int32_Neg1, fnname: "and_int32_Neg1", in: 0, want: 0},
+ test_int32{fn: and_Neg1_int32, fnname: "and_Neg1_int32", in: 1, want: 1},
+ test_int32{fn: and_int32_Neg1, fnname: "and_int32_Neg1", in: 1, want: 1},
+ test_int32{fn: and_Neg1_int32, fnname: "and_Neg1_int32", in: 2147483647, want: 2147483647},
+ test_int32{fn: and_int32_Neg1, fnname: "and_int32_Neg1", in: 2147483647, want: 2147483647},
+ test_int32{fn: and_0_int32, fnname: "and_0_int32", in: -2147483648, want: 0},
+ test_int32{fn: and_int32_0, fnname: "and_int32_0", in: -2147483648, want: 0},
+ test_int32{fn: and_0_int32, fnname: "and_0_int32", in: -2147483647, want: 0},
+ test_int32{fn: and_int32_0, fnname: "and_int32_0", in: -2147483647, want: 0},
+ test_int32{fn: and_0_int32, fnname: "and_0_int32", in: -1, want: 0},
+ test_int32{fn: and_int32_0, fnname: "and_int32_0", in: -1, want: 0},
+ test_int32{fn: and_0_int32, fnname: "and_0_int32", in: 0, want: 0},
+ test_int32{fn: and_int32_0, fnname: "and_int32_0", in: 0, want: 0},
+ test_int32{fn: and_0_int32, fnname: "and_0_int32", in: 1, want: 0},
+ test_int32{fn: and_int32_0, fnname: "and_int32_0", in: 1, want: 0},
+ test_int32{fn: and_0_int32, fnname: "and_0_int32", in: 2147483647, want: 0},
+ test_int32{fn: and_int32_0, fnname: "and_int32_0", in: 2147483647, want: 0},
+ test_int32{fn: and_1_int32, fnname: "and_1_int32", in: -2147483648, want: 0},
+ test_int32{fn: and_int32_1, fnname: "and_int32_1", in: -2147483648, want: 0},
+ test_int32{fn: and_1_int32, fnname: "and_1_int32", in: -2147483647, want: 1},
+ test_int32{fn: and_int32_1, fnname: "and_int32_1", in: -2147483647, want: 1},
+ test_int32{fn: and_1_int32, fnname: "and_1_int32", in: -1, want: 1},
+ test_int32{fn: and_int32_1, fnname: "and_int32_1", in: -1, want: 1},
+ test_int32{fn: and_1_int32, fnname: "and_1_int32", in: 0, want: 0},
+ test_int32{fn: and_int32_1, fnname: "and_int32_1", in: 0, want: 0},
+ test_int32{fn: and_1_int32, fnname: "and_1_int32", in: 1, want: 1},
+ test_int32{fn: and_int32_1, fnname: "and_int32_1", in: 1, want: 1},
+ test_int32{fn: and_1_int32, fnname: "and_1_int32", in: 2147483647, want: 1},
+ test_int32{fn: and_int32_1, fnname: "and_int32_1", in: 2147483647, want: 1},
+ test_int32{fn: and_2147483647_int32, fnname: "and_2147483647_int32", in: -2147483648, want: 0},
+ test_int32{fn: and_int32_2147483647, fnname: "and_int32_2147483647", in: -2147483648, want: 0},
+ test_int32{fn: and_2147483647_int32, fnname: "and_2147483647_int32", in: -2147483647, want: 1},
+ test_int32{fn: and_int32_2147483647, fnname: "and_int32_2147483647", in: -2147483647, want: 1},
+ test_int32{fn: and_2147483647_int32, fnname: "and_2147483647_int32", in: -1, want: 2147483647},
+ test_int32{fn: and_int32_2147483647, fnname: "and_int32_2147483647", in: -1, want: 2147483647},
+ test_int32{fn: and_2147483647_int32, fnname: "and_2147483647_int32", in: 0, want: 0},
+ test_int32{fn: and_int32_2147483647, fnname: "and_int32_2147483647", in: 0, want: 0},
+ test_int32{fn: and_2147483647_int32, fnname: "and_2147483647_int32", in: 1, want: 1},
+ test_int32{fn: and_int32_2147483647, fnname: "and_int32_2147483647", in: 1, want: 1},
+ test_int32{fn: and_2147483647_int32, fnname: "and_2147483647_int32", in: 2147483647, want: 2147483647},
+ test_int32{fn: and_int32_2147483647, fnname: "and_int32_2147483647", in: 2147483647, want: 2147483647},
+ test_int32{fn: or_Neg2147483648_int32, fnname: "or_Neg2147483648_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: or_int32_Neg2147483648, fnname: "or_int32_Neg2147483648", in: -2147483648, want: -2147483648},
+ test_int32{fn: or_Neg2147483648_int32, fnname: "or_Neg2147483648_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: or_int32_Neg2147483648, fnname: "or_int32_Neg2147483648", in: -2147483647, want: -2147483647},
+ test_int32{fn: or_Neg2147483648_int32, fnname: "or_Neg2147483648_int32", in: -1, want: -1},
+ test_int32{fn: or_int32_Neg2147483648, fnname: "or_int32_Neg2147483648", in: -1, want: -1},
+ test_int32{fn: or_Neg2147483648_int32, fnname: "or_Neg2147483648_int32", in: 0, want: -2147483648},
+ test_int32{fn: or_int32_Neg2147483648, fnname: "or_int32_Neg2147483648", in: 0, want: -2147483648},
+ test_int32{fn: or_Neg2147483648_int32, fnname: "or_Neg2147483648_int32", in: 1, want: -2147483647},
+ test_int32{fn: or_int32_Neg2147483648, fnname: "or_int32_Neg2147483648", in: 1, want: -2147483647},
+ test_int32{fn: or_Neg2147483648_int32, fnname: "or_Neg2147483648_int32", in: 2147483647, want: -1},
+ test_int32{fn: or_int32_Neg2147483648, fnname: "or_int32_Neg2147483648", in: 2147483647, want: -1},
+ test_int32{fn: or_Neg2147483647_int32, fnname: "or_Neg2147483647_int32", in: -2147483648, want: -2147483647},
+ test_int32{fn: or_int32_Neg2147483647, fnname: "or_int32_Neg2147483647", in: -2147483648, want: -2147483647},
+ test_int32{fn: or_Neg2147483647_int32, fnname: "or_Neg2147483647_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: or_int32_Neg2147483647, fnname: "or_int32_Neg2147483647", in: -2147483647, want: -2147483647},
+ test_int32{fn: or_Neg2147483647_int32, fnname: "or_Neg2147483647_int32", in: -1, want: -1},
+ test_int32{fn: or_int32_Neg2147483647, fnname: "or_int32_Neg2147483647", in: -1, want: -1},
+ test_int32{fn: or_Neg2147483647_int32, fnname: "or_Neg2147483647_int32", in: 0, want: -2147483647},
+ test_int32{fn: or_int32_Neg2147483647, fnname: "or_int32_Neg2147483647", in: 0, want: -2147483647},
+ test_int32{fn: or_Neg2147483647_int32, fnname: "or_Neg2147483647_int32", in: 1, want: -2147483647},
+ test_int32{fn: or_int32_Neg2147483647, fnname: "or_int32_Neg2147483647", in: 1, want: -2147483647},
+ test_int32{fn: or_Neg2147483647_int32, fnname: "or_Neg2147483647_int32", in: 2147483647, want: -1},
+ test_int32{fn: or_int32_Neg2147483647, fnname: "or_int32_Neg2147483647", in: 2147483647, want: -1},
+ test_int32{fn: or_Neg1_int32, fnname: "or_Neg1_int32", in: -2147483648, want: -1},
+ test_int32{fn: or_int32_Neg1, fnname: "or_int32_Neg1", in: -2147483648, want: -1},
+ test_int32{fn: or_Neg1_int32, fnname: "or_Neg1_int32", in: -2147483647, want: -1},
+ test_int32{fn: or_int32_Neg1, fnname: "or_int32_Neg1", in: -2147483647, want: -1},
+ test_int32{fn: or_Neg1_int32, fnname: "or_Neg1_int32", in: -1, want: -1},
+ test_int32{fn: or_int32_Neg1, fnname: "or_int32_Neg1", in: -1, want: -1},
+ test_int32{fn: or_Neg1_int32, fnname: "or_Neg1_int32", in: 0, want: -1},
+ test_int32{fn: or_int32_Neg1, fnname: "or_int32_Neg1", in: 0, want: -1},
+ test_int32{fn: or_Neg1_int32, fnname: "or_Neg1_int32", in: 1, want: -1},
+ test_int32{fn: or_int32_Neg1, fnname: "or_int32_Neg1", in: 1, want: -1},
+ test_int32{fn: or_Neg1_int32, fnname: "or_Neg1_int32", in: 2147483647, want: -1},
+ test_int32{fn: or_int32_Neg1, fnname: "or_int32_Neg1", in: 2147483647, want: -1},
+ test_int32{fn: or_0_int32, fnname: "or_0_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: or_int32_0, fnname: "or_int32_0", in: -2147483648, want: -2147483648},
+ test_int32{fn: or_0_int32, fnname: "or_0_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: or_int32_0, fnname: "or_int32_0", in: -2147483647, want: -2147483647},
+ test_int32{fn: or_0_int32, fnname: "or_0_int32", in: -1, want: -1},
+ test_int32{fn: or_int32_0, fnname: "or_int32_0", in: -1, want: -1},
+ test_int32{fn: or_0_int32, fnname: "or_0_int32", in: 0, want: 0},
+ test_int32{fn: or_int32_0, fnname: "or_int32_0", in: 0, want: 0},
+ test_int32{fn: or_0_int32, fnname: "or_0_int32", in: 1, want: 1},
+ test_int32{fn: or_int32_0, fnname: "or_int32_0", in: 1, want: 1},
+ test_int32{fn: or_0_int32, fnname: "or_0_int32", in: 2147483647, want: 2147483647},
+ test_int32{fn: or_int32_0, fnname: "or_int32_0", in: 2147483647, want: 2147483647},
+ test_int32{fn: or_1_int32, fnname: "or_1_int32", in: -2147483648, want: -2147483647},
+ test_int32{fn: or_int32_1, fnname: "or_int32_1", in: -2147483648, want: -2147483647},
+ test_int32{fn: or_1_int32, fnname: "or_1_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: or_int32_1, fnname: "or_int32_1", in: -2147483647, want: -2147483647},
+ test_int32{fn: or_1_int32, fnname: "or_1_int32", in: -1, want: -1},
+ test_int32{fn: or_int32_1, fnname: "or_int32_1", in: -1, want: -1},
+ test_int32{fn: or_1_int32, fnname: "or_1_int32", in: 0, want: 1},
+ test_int32{fn: or_int32_1, fnname: "or_int32_1", in: 0, want: 1},
+ test_int32{fn: or_1_int32, fnname: "or_1_int32", in: 1, want: 1},
+ test_int32{fn: or_int32_1, fnname: "or_int32_1", in: 1, want: 1},
+ test_int32{fn: or_1_int32, fnname: "or_1_int32", in: 2147483647, want: 2147483647},
+ test_int32{fn: or_int32_1, fnname: "or_int32_1", in: 2147483647, want: 2147483647},
+ test_int32{fn: or_2147483647_int32, fnname: "or_2147483647_int32", in: -2147483648, want: -1},
+ test_int32{fn: or_int32_2147483647, fnname: "or_int32_2147483647", in: -2147483648, want: -1},
+ test_int32{fn: or_2147483647_int32, fnname: "or_2147483647_int32", in: -2147483647, want: -1},
+ test_int32{fn: or_int32_2147483647, fnname: "or_int32_2147483647", in: -2147483647, want: -1},
+ test_int32{fn: or_2147483647_int32, fnname: "or_2147483647_int32", in: -1, want: -1},
+ test_int32{fn: or_int32_2147483647, fnname: "or_int32_2147483647", in: -1, want: -1},
+ test_int32{fn: or_2147483647_int32, fnname: "or_2147483647_int32", in: 0, want: 2147483647},
+ test_int32{fn: or_int32_2147483647, fnname: "or_int32_2147483647", in: 0, want: 2147483647},
+ test_int32{fn: or_2147483647_int32, fnname: "or_2147483647_int32", in: 1, want: 2147483647},
+ test_int32{fn: or_int32_2147483647, fnname: "or_int32_2147483647", in: 1, want: 2147483647},
+ test_int32{fn: or_2147483647_int32, fnname: "or_2147483647_int32", in: 2147483647, want: 2147483647},
+ test_int32{fn: or_int32_2147483647, fnname: "or_int32_2147483647", in: 2147483647, want: 2147483647},
+ test_int32{fn: xor_Neg2147483648_int32, fnname: "xor_Neg2147483648_int32", in: -2147483648, want: 0},
+ test_int32{fn: xor_int32_Neg2147483648, fnname: "xor_int32_Neg2147483648", in: -2147483648, want: 0},
+ test_int32{fn: xor_Neg2147483648_int32, fnname: "xor_Neg2147483648_int32", in: -2147483647, want: 1},
+ test_int32{fn: xor_int32_Neg2147483648, fnname: "xor_int32_Neg2147483648", in: -2147483647, want: 1},
+ test_int32{fn: xor_Neg2147483648_int32, fnname: "xor_Neg2147483648_int32", in: -1, want: 2147483647},
+ test_int32{fn: xor_int32_Neg2147483648, fnname: "xor_int32_Neg2147483648", in: -1, want: 2147483647},
+ test_int32{fn: xor_Neg2147483648_int32, fnname: "xor_Neg2147483648_int32", in: 0, want: -2147483648},
+ test_int32{fn: xor_int32_Neg2147483648, fnname: "xor_int32_Neg2147483648", in: 0, want: -2147483648},
+ test_int32{fn: xor_Neg2147483648_int32, fnname: "xor_Neg2147483648_int32", in: 1, want: -2147483647},
+ test_int32{fn: xor_int32_Neg2147483648, fnname: "xor_int32_Neg2147483648", in: 1, want: -2147483647},
+ test_int32{fn: xor_Neg2147483648_int32, fnname: "xor_Neg2147483648_int32", in: 2147483647, want: -1},
+ test_int32{fn: xor_int32_Neg2147483648, fnname: "xor_int32_Neg2147483648", in: 2147483647, want: -1},
+ test_int32{fn: xor_Neg2147483647_int32, fnname: "xor_Neg2147483647_int32", in: -2147483648, want: 1},
+ test_int32{fn: xor_int32_Neg2147483647, fnname: "xor_int32_Neg2147483647", in: -2147483648, want: 1},
+ test_int32{fn: xor_Neg2147483647_int32, fnname: "xor_Neg2147483647_int32", in: -2147483647, want: 0},
+ test_int32{fn: xor_int32_Neg2147483647, fnname: "xor_int32_Neg2147483647", in: -2147483647, want: 0},
+ test_int32{fn: xor_Neg2147483647_int32, fnname: "xor_Neg2147483647_int32", in: -1, want: 2147483646},
+ test_int32{fn: xor_int32_Neg2147483647, fnname: "xor_int32_Neg2147483647", in: -1, want: 2147483646},
+ test_int32{fn: xor_Neg2147483647_int32, fnname: "xor_Neg2147483647_int32", in: 0, want: -2147483647},
+ test_int32{fn: xor_int32_Neg2147483647, fnname: "xor_int32_Neg2147483647", in: 0, want: -2147483647},
+ test_int32{fn: xor_Neg2147483647_int32, fnname: "xor_Neg2147483647_int32", in: 1, want: -2147483648},
+ test_int32{fn: xor_int32_Neg2147483647, fnname: "xor_int32_Neg2147483647", in: 1, want: -2147483648},
+ test_int32{fn: xor_Neg2147483647_int32, fnname: "xor_Neg2147483647_int32", in: 2147483647, want: -2},
+ test_int32{fn: xor_int32_Neg2147483647, fnname: "xor_int32_Neg2147483647", in: 2147483647, want: -2},
+ test_int32{fn: xor_Neg1_int32, fnname: "xor_Neg1_int32", in: -2147483648, want: 2147483647},
+ test_int32{fn: xor_int32_Neg1, fnname: "xor_int32_Neg1", in: -2147483648, want: 2147483647},
+ test_int32{fn: xor_Neg1_int32, fnname: "xor_Neg1_int32", in: -2147483647, want: 2147483646},
+ test_int32{fn: xor_int32_Neg1, fnname: "xor_int32_Neg1", in: -2147483647, want: 2147483646},
+ test_int32{fn: xor_Neg1_int32, fnname: "xor_Neg1_int32", in: -1, want: 0},
+ test_int32{fn: xor_int32_Neg1, fnname: "xor_int32_Neg1", in: -1, want: 0},
+ test_int32{fn: xor_Neg1_int32, fnname: "xor_Neg1_int32", in: 0, want: -1},
+ test_int32{fn: xor_int32_Neg1, fnname: "xor_int32_Neg1", in: 0, want: -1},
+ test_int32{fn: xor_Neg1_int32, fnname: "xor_Neg1_int32", in: 1, want: -2},
+ test_int32{fn: xor_int32_Neg1, fnname: "xor_int32_Neg1", in: 1, want: -2},
+ test_int32{fn: xor_Neg1_int32, fnname: "xor_Neg1_int32", in: 2147483647, want: -2147483648},
+ test_int32{fn: xor_int32_Neg1, fnname: "xor_int32_Neg1", in: 2147483647, want: -2147483648},
+ test_int32{fn: xor_0_int32, fnname: "xor_0_int32", in: -2147483648, want: -2147483648},
+ test_int32{fn: xor_int32_0, fnname: "xor_int32_0", in: -2147483648, want: -2147483648},
+ test_int32{fn: xor_0_int32, fnname: "xor_0_int32", in: -2147483647, want: -2147483647},
+ test_int32{fn: xor_int32_0, fnname: "xor_int32_0", in: -2147483647, want: -2147483647},
+ test_int32{fn: xor_0_int32, fnname: "xor_0_int32", in: -1, want: -1},
+ test_int32{fn: xor_int32_0, fnname: "xor_int32_0", in: -1, want: -1},
+ test_int32{fn: xor_0_int32, fnname: "xor_0_int32", in: 0, want: 0},
+ test_int32{fn: xor_int32_0, fnname: "xor_int32_0", in: 0, want: 0},
+ test_int32{fn: xor_0_int32, fnname: "xor_0_int32", in: 1, want: 1},
+ test_int32{fn: xor_int32_0, fnname: "xor_int32_0", in: 1, want: 1},
+ test_int32{fn: xor_0_int32, fnname: "xor_0_int32", in: 2147483647, want: 2147483647},
+ test_int32{fn: xor_int32_0, fnname: "xor_int32_0", in: 2147483647, want: 2147483647},
+ test_int32{fn: xor_1_int32, fnname: "xor_1_int32", in: -2147483648, want: -2147483647},
+ test_int32{fn: xor_int32_1, fnname: "xor_int32_1", in: -2147483648, want: -2147483647},
+ test_int32{fn: xor_1_int32, fnname: "xor_1_int32", in: -2147483647, want: -2147483648},
+ test_int32{fn: xor_int32_1, fnname: "xor_int32_1", in: -2147483647, want: -2147483648},
+ test_int32{fn: xor_1_int32, fnname: "xor_1_int32", in: -1, want: -2},
+ test_int32{fn: xor_int32_1, fnname: "xor_int32_1", in: -1, want: -2},
+ test_int32{fn: xor_1_int32, fnname: "xor_1_int32", in: 0, want: 1},
+ test_int32{fn: xor_int32_1, fnname: "xor_int32_1", in: 0, want: 1},
+ test_int32{fn: xor_1_int32, fnname: "xor_1_int32", in: 1, want: 0},
+ test_int32{fn: xor_int32_1, fnname: "xor_int32_1", in: 1, want: 0},
+ test_int32{fn: xor_1_int32, fnname: "xor_1_int32", in: 2147483647, want: 2147483646},
+ test_int32{fn: xor_int32_1, fnname: "xor_int32_1", in: 2147483647, want: 2147483646},
+ test_int32{fn: xor_2147483647_int32, fnname: "xor_2147483647_int32", in: -2147483648, want: -1},
+ test_int32{fn: xor_int32_2147483647, fnname: "xor_int32_2147483647", in: -2147483648, want: -1},
+ test_int32{fn: xor_2147483647_int32, fnname: "xor_2147483647_int32", in: -2147483647, want: -2},
+ test_int32{fn: xor_int32_2147483647, fnname: "xor_int32_2147483647", in: -2147483647, want: -2},
+ test_int32{fn: xor_2147483647_int32, fnname: "xor_2147483647_int32", in: -1, want: -2147483648},
+ test_int32{fn: xor_int32_2147483647, fnname: "xor_int32_2147483647", in: -1, want: -2147483648},
+ test_int32{fn: xor_2147483647_int32, fnname: "xor_2147483647_int32", in: 0, want: 2147483647},
+ test_int32{fn: xor_int32_2147483647, fnname: "xor_int32_2147483647", in: 0, want: 2147483647},
+ test_int32{fn: xor_2147483647_int32, fnname: "xor_2147483647_int32", in: 1, want: 2147483646},
+ test_int32{fn: xor_int32_2147483647, fnname: "xor_int32_2147483647", in: 1, want: 2147483646},
+ test_int32{fn: xor_2147483647_int32, fnname: "xor_2147483647_int32", in: 2147483647, want: 0},
+ test_int32{fn: xor_int32_2147483647, fnname: "xor_int32_2147483647", in: 2147483647, want: 0}}
+
+type test_int32mul struct {
+ fn func(int32) int32
+ fnname string
+ in int32
+ want int32
+}
+
+var tests_int32mul = []test_int32{
+
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: -9, want: 81},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: -9, want: 81},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: -5, want: 45},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: -5, want: 45},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: -3, want: 27},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: -3, want: 27},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 3, want: -27},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 3, want: -27},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 5, want: -45},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 5, want: -45},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 7, want: -63},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 7, want: -63},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 9, want: -81},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 9, want: -81},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 10, want: -90},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 10, want: -90},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 11, want: -99},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 11, want: -99},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 13, want: -117},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 13, want: -117},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 19, want: -171},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 19, want: -171},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 21, want: -189},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 21, want: -189},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 25, want: -225},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 25, want: -225},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 27, want: -243},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 27, want: -243},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 37, want: -333},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 37, want: -333},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 41, want: -369},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 41, want: -369},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 45, want: -405},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 45, want: -405},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 73, want: -657},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 73, want: -657},
+ test_int32{fn: mul_Neg9_int32, fnname: "mul_Neg9_int32", in: 81, want: -729},
+ test_int32{fn: mul_int32_Neg9, fnname: "mul_int32_Neg9", in: 81, want: -729},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: -9, want: 45},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: -9, want: 45},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: -5, want: 25},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: -5, want: 25},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: -3, want: 15},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: -3, want: 15},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 3, want: -15},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 3, want: -15},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 5, want: -25},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 5, want: -25},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 7, want: -35},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 7, want: -35},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 9, want: -45},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 9, want: -45},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 10, want: -50},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 10, want: -50},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 11, want: -55},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 11, want: -55},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 13, want: -65},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 13, want: -65},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 19, want: -95},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 19, want: -95},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 21, want: -105},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 21, want: -105},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 25, want: -125},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 25, want: -125},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 27, want: -135},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 27, want: -135},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 37, want: -185},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 37, want: -185},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 41, want: -205},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 41, want: -205},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 45, want: -225},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 45, want: -225},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 73, want: -365},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 73, want: -365},
+ test_int32{fn: mul_Neg5_int32, fnname: "mul_Neg5_int32", in: 81, want: -405},
+ test_int32{fn: mul_int32_Neg5, fnname: "mul_int32_Neg5", in: 81, want: -405},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: -9, want: 27},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: -9, want: 27},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: -5, want: 15},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: -5, want: 15},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: -3, want: 9},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: -3, want: 9},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 3, want: -9},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 3, want: -9},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 5, want: -15},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 5, want: -15},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 7, want: -21},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 7, want: -21},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 9, want: -27},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 9, want: -27},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 10, want: -30},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 10, want: -30},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 11, want: -33},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 11, want: -33},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 13, want: -39},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 13, want: -39},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 19, want: -57},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 19, want: -57},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 21, want: -63},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 21, want: -63},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 25, want: -75},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 25, want: -75},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 27, want: -81},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 27, want: -81},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 37, want: -111},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 37, want: -111},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 41, want: -123},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 41, want: -123},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 45, want: -135},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 45, want: -135},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 73, want: -219},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 73, want: -219},
+ test_int32{fn: mul_Neg3_int32, fnname: "mul_Neg3_int32", in: 81, want: -243},
+ test_int32{fn: mul_int32_Neg3, fnname: "mul_int32_Neg3", in: 81, want: -243},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: -9, want: -27},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: -9, want: -27},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: -5, want: -15},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: -5, want: -15},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: -3, want: -9},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: -3, want: -9},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 3, want: 9},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 3, want: 9},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 5, want: 15},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 5, want: 15},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 7, want: 21},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 7, want: 21},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 9, want: 27},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 9, want: 27},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 10, want: 30},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 10, want: 30},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 11, want: 33},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 11, want: 33},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 13, want: 39},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 13, want: 39},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 19, want: 57},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 19, want: 57},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 21, want: 63},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 21, want: 63},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 25, want: 75},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 25, want: 75},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 27, want: 81},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 27, want: 81},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 37, want: 111},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 37, want: 111},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 41, want: 123},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 41, want: 123},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 45, want: 135},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 45, want: 135},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 73, want: 219},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 73, want: 219},
+ test_int32{fn: mul_3_int32, fnname: "mul_3_int32", in: 81, want: 243},
+ test_int32{fn: mul_int32_3, fnname: "mul_int32_3", in: 81, want: 243},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: -9, want: -45},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: -9, want: -45},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: -5, want: -25},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: -5, want: -25},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: -3, want: -15},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: -3, want: -15},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 3, want: 15},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 3, want: 15},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 5, want: 25},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 5, want: 25},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 7, want: 35},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 7, want: 35},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 9, want: 45},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 9, want: 45},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 10, want: 50},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 10, want: 50},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 11, want: 55},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 11, want: 55},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 13, want: 65},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 13, want: 65},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 19, want: 95},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 19, want: 95},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 21, want: 105},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 21, want: 105},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 25, want: 125},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 25, want: 125},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 27, want: 135},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 27, want: 135},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 37, want: 185},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 37, want: 185},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 41, want: 205},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 41, want: 205},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 45, want: 225},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 45, want: 225},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 73, want: 365},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 73, want: 365},
+ test_int32{fn: mul_5_int32, fnname: "mul_5_int32", in: 81, want: 405},
+ test_int32{fn: mul_int32_5, fnname: "mul_int32_5", in: 81, want: 405},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: -9, want: -63},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: -9, want: -63},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: -5, want: -35},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: -5, want: -35},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: -3, want: -21},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: -3, want: -21},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 3, want: 21},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 3, want: 21},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 5, want: 35},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 5, want: 35},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 7, want: 49},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 7, want: 49},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 9, want: 63},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 9, want: 63},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 10, want: 70},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 10, want: 70},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 11, want: 77},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 11, want: 77},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 13, want: 91},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 13, want: 91},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 19, want: 133},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 19, want: 133},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 21, want: 147},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 21, want: 147},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 25, want: 175},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 25, want: 175},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 27, want: 189},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 27, want: 189},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 37, want: 259},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 37, want: 259},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 41, want: 287},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 41, want: 287},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 45, want: 315},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 45, want: 315},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 73, want: 511},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 73, want: 511},
+ test_int32{fn: mul_7_int32, fnname: "mul_7_int32", in: 81, want: 567},
+ test_int32{fn: mul_int32_7, fnname: "mul_int32_7", in: 81, want: 567},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: -9, want: -81},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: -9, want: -81},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: -5, want: -45},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: -5, want: -45},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: -3, want: -27},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: -3, want: -27},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 3, want: 27},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 3, want: 27},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 5, want: 45},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 5, want: 45},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 7, want: 63},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 7, want: 63},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 9, want: 81},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 9, want: 81},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 10, want: 90},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 10, want: 90},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 11, want: 99},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 11, want: 99},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 13, want: 117},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 13, want: 117},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 19, want: 171},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 19, want: 171},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 21, want: 189},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 21, want: 189},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 25, want: 225},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 25, want: 225},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 27, want: 243},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 27, want: 243},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 37, want: 333},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 37, want: 333},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 41, want: 369},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 41, want: 369},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 45, want: 405},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 45, want: 405},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 73, want: 657},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 73, want: 657},
+ test_int32{fn: mul_9_int32, fnname: "mul_9_int32", in: 81, want: 729},
+ test_int32{fn: mul_int32_9, fnname: "mul_int32_9", in: 81, want: 729},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: -9, want: -90},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: -9, want: -90},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: -5, want: -50},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: -5, want: -50},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: -3, want: -30},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: -3, want: -30},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 3, want: 30},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 3, want: 30},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 5, want: 50},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 5, want: 50},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 7, want: 70},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 7, want: 70},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 9, want: 90},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 9, want: 90},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 10, want: 100},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 10, want: 100},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 11, want: 110},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 11, want: 110},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 13, want: 130},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 13, want: 130},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 19, want: 190},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 19, want: 190},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 21, want: 210},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 21, want: 210},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 25, want: 250},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 25, want: 250},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 27, want: 270},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 27, want: 270},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 37, want: 370},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 37, want: 370},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 41, want: 410},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 41, want: 410},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 45, want: 450},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 45, want: 450},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 73, want: 730},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 73, want: 730},
+ test_int32{fn: mul_10_int32, fnname: "mul_10_int32", in: 81, want: 810},
+ test_int32{fn: mul_int32_10, fnname: "mul_int32_10", in: 81, want: 810},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: -9, want: -99},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: -9, want: -99},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: -5, want: -55},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: -5, want: -55},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: -3, want: -33},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: -3, want: -33},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 3, want: 33},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 3, want: 33},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 5, want: 55},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 5, want: 55},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 7, want: 77},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 7, want: 77},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 9, want: 99},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 9, want: 99},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 10, want: 110},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 10, want: 110},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 11, want: 121},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 11, want: 121},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 13, want: 143},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 13, want: 143},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 19, want: 209},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 19, want: 209},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 21, want: 231},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 21, want: 231},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 25, want: 275},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 25, want: 275},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 27, want: 297},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 27, want: 297},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 37, want: 407},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 37, want: 407},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 41, want: 451},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 41, want: 451},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 45, want: 495},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 45, want: 495},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 73, want: 803},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 73, want: 803},
+ test_int32{fn: mul_11_int32, fnname: "mul_11_int32", in: 81, want: 891},
+ test_int32{fn: mul_int32_11, fnname: "mul_int32_11", in: 81, want: 891},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: -9, want: -117},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: -9, want: -117},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: -5, want: -65},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: -5, want: -65},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: -3, want: -39},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: -3, want: -39},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 3, want: 39},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 3, want: 39},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 5, want: 65},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 5, want: 65},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 7, want: 91},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 7, want: 91},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 9, want: 117},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 9, want: 117},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 10, want: 130},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 10, want: 130},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 11, want: 143},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 11, want: 143},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 13, want: 169},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 13, want: 169},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 19, want: 247},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 19, want: 247},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 21, want: 273},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 21, want: 273},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 25, want: 325},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 25, want: 325},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 27, want: 351},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 27, want: 351},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 37, want: 481},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 37, want: 481},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 41, want: 533},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 41, want: 533},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 45, want: 585},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 45, want: 585},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 73, want: 949},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 73, want: 949},
+ test_int32{fn: mul_13_int32, fnname: "mul_13_int32", in: 81, want: 1053},
+ test_int32{fn: mul_int32_13, fnname: "mul_int32_13", in: 81, want: 1053},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: -9, want: -171},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: -9, want: -171},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: -5, want: -95},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: -5, want: -95},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: -3, want: -57},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: -3, want: -57},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 3, want: 57},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 3, want: 57},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 5, want: 95},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 5, want: 95},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 7, want: 133},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 7, want: 133},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 9, want: 171},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 9, want: 171},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 10, want: 190},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 10, want: 190},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 11, want: 209},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 11, want: 209},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 13, want: 247},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 13, want: 247},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 19, want: 361},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 19, want: 361},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 21, want: 399},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 21, want: 399},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 25, want: 475},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 25, want: 475},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 27, want: 513},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 27, want: 513},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 37, want: 703},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 37, want: 703},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 41, want: 779},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 41, want: 779},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 45, want: 855},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 45, want: 855},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 73, want: 1387},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 73, want: 1387},
+ test_int32{fn: mul_19_int32, fnname: "mul_19_int32", in: 81, want: 1539},
+ test_int32{fn: mul_int32_19, fnname: "mul_int32_19", in: 81, want: 1539},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: -9, want: -189},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: -9, want: -189},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: -5, want: -105},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: -5, want: -105},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: -3, want: -63},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: -3, want: -63},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 3, want: 63},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 3, want: 63},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 5, want: 105},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 5, want: 105},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 7, want: 147},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 7, want: 147},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 9, want: 189},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 9, want: 189},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 10, want: 210},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 10, want: 210},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 11, want: 231},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 11, want: 231},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 13, want: 273},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 13, want: 273},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 19, want: 399},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 19, want: 399},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 21, want: 441},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 21, want: 441},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 25, want: 525},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 25, want: 525},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 27, want: 567},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 27, want: 567},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 37, want: 777},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 37, want: 777},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 41, want: 861},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 41, want: 861},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 45, want: 945},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 45, want: 945},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 73, want: 1533},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 73, want: 1533},
+ test_int32{fn: mul_21_int32, fnname: "mul_21_int32", in: 81, want: 1701},
+ test_int32{fn: mul_int32_21, fnname: "mul_int32_21", in: 81, want: 1701},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: -9, want: -225},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: -9, want: -225},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: -5, want: -125},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: -5, want: -125},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: -3, want: -75},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: -3, want: -75},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 3, want: 75},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 3, want: 75},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 5, want: 125},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 5, want: 125},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 7, want: 175},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 7, want: 175},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 9, want: 225},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 9, want: 225},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 10, want: 250},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 10, want: 250},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 11, want: 275},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 11, want: 275},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 13, want: 325},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 13, want: 325},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 19, want: 475},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 19, want: 475},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 21, want: 525},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 21, want: 525},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 25, want: 625},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 25, want: 625},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 27, want: 675},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 27, want: 675},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 37, want: 925},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 37, want: 925},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 41, want: 1025},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 41, want: 1025},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 45, want: 1125},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 45, want: 1125},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 73, want: 1825},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 73, want: 1825},
+ test_int32{fn: mul_25_int32, fnname: "mul_25_int32", in: 81, want: 2025},
+ test_int32{fn: mul_int32_25, fnname: "mul_int32_25", in: 81, want: 2025},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: -9, want: -243},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: -9, want: -243},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: -5, want: -135},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: -5, want: -135},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: -3, want: -81},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: -3, want: -81},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 3, want: 81},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 3, want: 81},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 5, want: 135},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 5, want: 135},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 7, want: 189},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 7, want: 189},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 9, want: 243},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 9, want: 243},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 10, want: 270},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 10, want: 270},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 11, want: 297},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 11, want: 297},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 13, want: 351},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 13, want: 351},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 19, want: 513},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 19, want: 513},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 21, want: 567},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 21, want: 567},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 25, want: 675},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 25, want: 675},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 27, want: 729},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 27, want: 729},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 37, want: 999},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 37, want: 999},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 41, want: 1107},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 41, want: 1107},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 45, want: 1215},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 45, want: 1215},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 73, want: 1971},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 73, want: 1971},
+ test_int32{fn: mul_27_int32, fnname: "mul_27_int32", in: 81, want: 2187},
+ test_int32{fn: mul_int32_27, fnname: "mul_int32_27", in: 81, want: 2187},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: -9, want: -333},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: -9, want: -333},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: -5, want: -185},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: -5, want: -185},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: -3, want: -111},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: -3, want: -111},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 3, want: 111},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 3, want: 111},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 5, want: 185},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 5, want: 185},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 7, want: 259},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 7, want: 259},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 9, want: 333},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 9, want: 333},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 10, want: 370},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 10, want: 370},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 11, want: 407},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 11, want: 407},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 13, want: 481},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 13, want: 481},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 19, want: 703},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 19, want: 703},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 21, want: 777},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 21, want: 777},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 25, want: 925},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 25, want: 925},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 27, want: 999},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 27, want: 999},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 37, want: 1369},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 37, want: 1369},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 41, want: 1517},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 41, want: 1517},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 45, want: 1665},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 45, want: 1665},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 73, want: 2701},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 73, want: 2701},
+ test_int32{fn: mul_37_int32, fnname: "mul_37_int32", in: 81, want: 2997},
+ test_int32{fn: mul_int32_37, fnname: "mul_int32_37", in: 81, want: 2997},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: -9, want: -369},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: -9, want: -369},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: -5, want: -205},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: -5, want: -205},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: -3, want: -123},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: -3, want: -123},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 3, want: 123},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 3, want: 123},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 5, want: 205},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 5, want: 205},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 7, want: 287},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 7, want: 287},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 9, want: 369},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 9, want: 369},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 10, want: 410},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 10, want: 410},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 11, want: 451},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 11, want: 451},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 13, want: 533},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 13, want: 533},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 19, want: 779},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 19, want: 779},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 21, want: 861},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 21, want: 861},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 25, want: 1025},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 25, want: 1025},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 27, want: 1107},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 27, want: 1107},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 37, want: 1517},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 37, want: 1517},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 41, want: 1681},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 41, want: 1681},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 45, want: 1845},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 45, want: 1845},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 73, want: 2993},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 73, want: 2993},
+ test_int32{fn: mul_41_int32, fnname: "mul_41_int32", in: 81, want: 3321},
+ test_int32{fn: mul_int32_41, fnname: "mul_int32_41", in: 81, want: 3321},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: -9, want: -405},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: -9, want: -405},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: -5, want: -225},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: -5, want: -225},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: -3, want: -135},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: -3, want: -135},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 3, want: 135},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 3, want: 135},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 5, want: 225},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 5, want: 225},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 7, want: 315},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 7, want: 315},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 9, want: 405},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 9, want: 405},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 10, want: 450},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 10, want: 450},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 11, want: 495},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 11, want: 495},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 13, want: 585},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 13, want: 585},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 19, want: 855},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 19, want: 855},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 21, want: 945},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 21, want: 945},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 25, want: 1125},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 25, want: 1125},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 27, want: 1215},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 27, want: 1215},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 37, want: 1665},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 37, want: 1665},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 41, want: 1845},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 41, want: 1845},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 45, want: 2025},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 45, want: 2025},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 73, want: 3285},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 73, want: 3285},
+ test_int32{fn: mul_45_int32, fnname: "mul_45_int32", in: 81, want: 3645},
+ test_int32{fn: mul_int32_45, fnname: "mul_int32_45", in: 81, want: 3645},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: -9, want: -657},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: -9, want: -657},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: -5, want: -365},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: -5, want: -365},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: -3, want: -219},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: -3, want: -219},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 3, want: 219},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 3, want: 219},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 5, want: 365},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 5, want: 365},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 7, want: 511},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 7, want: 511},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 9, want: 657},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 9, want: 657},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 10, want: 730},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 10, want: 730},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 11, want: 803},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 11, want: 803},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 13, want: 949},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 13, want: 949},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 19, want: 1387},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 19, want: 1387},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 21, want: 1533},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 21, want: 1533},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 25, want: 1825},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 25, want: 1825},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 27, want: 1971},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 27, want: 1971},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 37, want: 2701},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 37, want: 2701},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 41, want: 2993},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 41, want: 2993},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 45, want: 3285},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 45, want: 3285},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 73, want: 5329},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 73, want: 5329},
+ test_int32{fn: mul_73_int32, fnname: "mul_73_int32", in: 81, want: 5913},
+ test_int32{fn: mul_int32_73, fnname: "mul_int32_73", in: 81, want: 5913},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: -9, want: -729},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: -9, want: -729},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: -5, want: -405},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: -5, want: -405},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: -3, want: -243},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: -3, want: -243},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 3, want: 243},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 3, want: 243},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 5, want: 405},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 5, want: 405},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 7, want: 567},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 7, want: 567},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 9, want: 729},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 9, want: 729},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 10, want: 810},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 10, want: 810},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 11, want: 891},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 11, want: 891},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 13, want: 1053},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 13, want: 1053},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 19, want: 1539},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 19, want: 1539},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 21, want: 1701},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 21, want: 1701},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 25, want: 2025},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 25, want: 2025},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 27, want: 2187},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 27, want: 2187},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 37, want: 2997},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 37, want: 2997},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 41, want: 3321},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 41, want: 3321},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 45, want: 3645},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 45, want: 3645},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 73, want: 5913},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 73, want: 5913},
+ test_int32{fn: mul_81_int32, fnname: "mul_81_int32", in: 81, want: 6561},
+ test_int32{fn: mul_int32_81, fnname: "mul_int32_81", in: 81, want: 6561}}
+
+type test_uint16 struct {
+ fn func(uint16) uint16
+ fnname string
+ in uint16
+ want uint16
+}
+
+var tests_uint16 = []test_uint16{
+
+ test_uint16{fn: add_0_uint16, fnname: "add_0_uint16", in: 0, want: 0},
+ test_uint16{fn: add_uint16_0, fnname: "add_uint16_0", in: 0, want: 0},
+ test_uint16{fn: add_0_uint16, fnname: "add_0_uint16", in: 1, want: 1},
+ test_uint16{fn: add_uint16_0, fnname: "add_uint16_0", in: 1, want: 1},
+ test_uint16{fn: add_0_uint16, fnname: "add_0_uint16", in: 65535, want: 65535},
+ test_uint16{fn: add_uint16_0, fnname: "add_uint16_0", in: 65535, want: 65535},
+ test_uint16{fn: add_1_uint16, fnname: "add_1_uint16", in: 0, want: 1},
+ test_uint16{fn: add_uint16_1, fnname: "add_uint16_1", in: 0, want: 1},
+ test_uint16{fn: add_1_uint16, fnname: "add_1_uint16", in: 1, want: 2},
+ test_uint16{fn: add_uint16_1, fnname: "add_uint16_1", in: 1, want: 2},
+ test_uint16{fn: add_1_uint16, fnname: "add_1_uint16", in: 65535, want: 0},
+ test_uint16{fn: add_uint16_1, fnname: "add_uint16_1", in: 65535, want: 0},
+ test_uint16{fn: add_65535_uint16, fnname: "add_65535_uint16", in: 0, want: 65535},
+ test_uint16{fn: add_uint16_65535, fnname: "add_uint16_65535", in: 0, want: 65535},
+ test_uint16{fn: add_65535_uint16, fnname: "add_65535_uint16", in: 1, want: 0},
+ test_uint16{fn: add_uint16_65535, fnname: "add_uint16_65535", in: 1, want: 0},
+ test_uint16{fn: add_65535_uint16, fnname: "add_65535_uint16", in: 65535, want: 65534},
+ test_uint16{fn: add_uint16_65535, fnname: "add_uint16_65535", in: 65535, want: 65534},
+ test_uint16{fn: sub_0_uint16, fnname: "sub_0_uint16", in: 0, want: 0},
+ test_uint16{fn: sub_uint16_0, fnname: "sub_uint16_0", in: 0, want: 0},
+ test_uint16{fn: sub_0_uint16, fnname: "sub_0_uint16", in: 1, want: 65535},
+ test_uint16{fn: sub_uint16_0, fnname: "sub_uint16_0", in: 1, want: 1},
+ test_uint16{fn: sub_0_uint16, fnname: "sub_0_uint16", in: 65535, want: 1},
+ test_uint16{fn: sub_uint16_0, fnname: "sub_uint16_0", in: 65535, want: 65535},
+ test_uint16{fn: sub_1_uint16, fnname: "sub_1_uint16", in: 0, want: 1},
+ test_uint16{fn: sub_uint16_1, fnname: "sub_uint16_1", in: 0, want: 65535},
+ test_uint16{fn: sub_1_uint16, fnname: "sub_1_uint16", in: 1, want: 0},
+ test_uint16{fn: sub_uint16_1, fnname: "sub_uint16_1", in: 1, want: 0},
+ test_uint16{fn: sub_1_uint16, fnname: "sub_1_uint16", in: 65535, want: 2},
+ test_uint16{fn: sub_uint16_1, fnname: "sub_uint16_1", in: 65535, want: 65534},
+ test_uint16{fn: sub_65535_uint16, fnname: "sub_65535_uint16", in: 0, want: 65535},
+ test_uint16{fn: sub_uint16_65535, fnname: "sub_uint16_65535", in: 0, want: 1},
+ test_uint16{fn: sub_65535_uint16, fnname: "sub_65535_uint16", in: 1, want: 65534},
+ test_uint16{fn: sub_uint16_65535, fnname: "sub_uint16_65535", in: 1, want: 2},
+ test_uint16{fn: sub_65535_uint16, fnname: "sub_65535_uint16", in: 65535, want: 0},
+ test_uint16{fn: sub_uint16_65535, fnname: "sub_uint16_65535", in: 65535, want: 0},
+ test_uint16{fn: div_0_uint16, fnname: "div_0_uint16", in: 1, want: 0},
+ test_uint16{fn: div_0_uint16, fnname: "div_0_uint16", in: 65535, want: 0},
+ test_uint16{fn: div_uint16_1, fnname: "div_uint16_1", in: 0, want: 0},
+ test_uint16{fn: div_1_uint16, fnname: "div_1_uint16", in: 1, want: 1},
+ test_uint16{fn: div_uint16_1, fnname: "div_uint16_1", in: 1, want: 1},
+ test_uint16{fn: div_1_uint16, fnname: "div_1_uint16", in: 65535, want: 0},
+ test_uint16{fn: div_uint16_1, fnname: "div_uint16_1", in: 65535, want: 65535},
+ test_uint16{fn: div_uint16_65535, fnname: "div_uint16_65535", in: 0, want: 0},
+ test_uint16{fn: div_65535_uint16, fnname: "div_65535_uint16", in: 1, want: 65535},
+ test_uint16{fn: div_uint16_65535, fnname: "div_uint16_65535", in: 1, want: 0},
+ test_uint16{fn: div_65535_uint16, fnname: "div_65535_uint16", in: 65535, want: 1},
+ test_uint16{fn: div_uint16_65535, fnname: "div_uint16_65535", in: 65535, want: 1},
+ test_uint16{fn: mul_0_uint16, fnname: "mul_0_uint16", in: 0, want: 0},
+ test_uint16{fn: mul_uint16_0, fnname: "mul_uint16_0", in: 0, want: 0},
+ test_uint16{fn: mul_0_uint16, fnname: "mul_0_uint16", in: 1, want: 0},
+ test_uint16{fn: mul_uint16_0, fnname: "mul_uint16_0", in: 1, want: 0},
+ test_uint16{fn: mul_0_uint16, fnname: "mul_0_uint16", in: 65535, want: 0},
+ test_uint16{fn: mul_uint16_0, fnname: "mul_uint16_0", in: 65535, want: 0},
+ test_uint16{fn: mul_1_uint16, fnname: "mul_1_uint16", in: 0, want: 0},
+ test_uint16{fn: mul_uint16_1, fnname: "mul_uint16_1", in: 0, want: 0},
+ test_uint16{fn: mul_1_uint16, fnname: "mul_1_uint16", in: 1, want: 1},
+ test_uint16{fn: mul_uint16_1, fnname: "mul_uint16_1", in: 1, want: 1},
+ test_uint16{fn: mul_1_uint16, fnname: "mul_1_uint16", in: 65535, want: 65535},
+ test_uint16{fn: mul_uint16_1, fnname: "mul_uint16_1", in: 65535, want: 65535},
+ test_uint16{fn: mul_65535_uint16, fnname: "mul_65535_uint16", in: 0, want: 0},
+ test_uint16{fn: mul_uint16_65535, fnname: "mul_uint16_65535", in: 0, want: 0},
+ test_uint16{fn: mul_65535_uint16, fnname: "mul_65535_uint16", in: 1, want: 65535},
+ test_uint16{fn: mul_uint16_65535, fnname: "mul_uint16_65535", in: 1, want: 65535},
+ test_uint16{fn: mul_65535_uint16, fnname: "mul_65535_uint16", in: 65535, want: 1},
+ test_uint16{fn: mul_uint16_65535, fnname: "mul_uint16_65535", in: 65535, want: 1},
+ test_uint16{fn: lsh_0_uint16, fnname: "lsh_0_uint16", in: 0, want: 0},
+ test_uint16{fn: lsh_uint16_0, fnname: "lsh_uint16_0", in: 0, want: 0},
+ test_uint16{fn: lsh_0_uint16, fnname: "lsh_0_uint16", in: 1, want: 0},
+ test_uint16{fn: lsh_uint16_0, fnname: "lsh_uint16_0", in: 1, want: 1},
+ test_uint16{fn: lsh_0_uint16, fnname: "lsh_0_uint16", in: 65535, want: 0},
+ test_uint16{fn: lsh_uint16_0, fnname: "lsh_uint16_0", in: 65535, want: 65535},
+ test_uint16{fn: lsh_1_uint16, fnname: "lsh_1_uint16", in: 0, want: 1},
+ test_uint16{fn: lsh_uint16_1, fnname: "lsh_uint16_1", in: 0, want: 0},
+ test_uint16{fn: lsh_1_uint16, fnname: "lsh_1_uint16", in: 1, want: 2},
+ test_uint16{fn: lsh_uint16_1, fnname: "lsh_uint16_1", in: 1, want: 2},
+ test_uint16{fn: lsh_1_uint16, fnname: "lsh_1_uint16", in: 65535, want: 0},
+ test_uint16{fn: lsh_uint16_1, fnname: "lsh_uint16_1", in: 65535, want: 65534},
+ test_uint16{fn: lsh_65535_uint16, fnname: "lsh_65535_uint16", in: 0, want: 65535},
+ test_uint16{fn: lsh_uint16_65535, fnname: "lsh_uint16_65535", in: 0, want: 0},
+ test_uint16{fn: lsh_65535_uint16, fnname: "lsh_65535_uint16", in: 1, want: 65534},
+ test_uint16{fn: lsh_uint16_65535, fnname: "lsh_uint16_65535", in: 1, want: 0},
+ test_uint16{fn: lsh_65535_uint16, fnname: "lsh_65535_uint16", in: 65535, want: 0},
+ test_uint16{fn: lsh_uint16_65535, fnname: "lsh_uint16_65535", in: 65535, want: 0},
+ test_uint16{fn: rsh_0_uint16, fnname: "rsh_0_uint16", in: 0, want: 0},
+ test_uint16{fn: rsh_uint16_0, fnname: "rsh_uint16_0", in: 0, want: 0},
+ test_uint16{fn: rsh_0_uint16, fnname: "rsh_0_uint16", in: 1, want: 0},
+ test_uint16{fn: rsh_uint16_0, fnname: "rsh_uint16_0", in: 1, want: 1},
+ test_uint16{fn: rsh_0_uint16, fnname: "rsh_0_uint16", in: 65535, want: 0},
+ test_uint16{fn: rsh_uint16_0, fnname: "rsh_uint16_0", in: 65535, want: 65535},
+ test_uint16{fn: rsh_1_uint16, fnname: "rsh_1_uint16", in: 0, want: 1},
+ test_uint16{fn: rsh_uint16_1, fnname: "rsh_uint16_1", in: 0, want: 0},
+ test_uint16{fn: rsh_1_uint16, fnname: "rsh_1_uint16", in: 1, want: 0},
+ test_uint16{fn: rsh_uint16_1, fnname: "rsh_uint16_1", in: 1, want: 0},
+ test_uint16{fn: rsh_1_uint16, fnname: "rsh_1_uint16", in: 65535, want: 0},
+ test_uint16{fn: rsh_uint16_1, fnname: "rsh_uint16_1", in: 65535, want: 32767},
+ test_uint16{fn: rsh_65535_uint16, fnname: "rsh_65535_uint16", in: 0, want: 65535},
+ test_uint16{fn: rsh_uint16_65535, fnname: "rsh_uint16_65535", in: 0, want: 0},
+ test_uint16{fn: rsh_65535_uint16, fnname: "rsh_65535_uint16", in: 1, want: 32767},
+ test_uint16{fn: rsh_uint16_65535, fnname: "rsh_uint16_65535", in: 1, want: 0},
+ test_uint16{fn: rsh_65535_uint16, fnname: "rsh_65535_uint16", in: 65535, want: 0},
+ test_uint16{fn: rsh_uint16_65535, fnname: "rsh_uint16_65535", in: 65535, want: 0},
+ test_uint16{fn: mod_0_uint16, fnname: "mod_0_uint16", in: 1, want: 0},
+ test_uint16{fn: mod_0_uint16, fnname: "mod_0_uint16", in: 65535, want: 0},
+ test_uint16{fn: mod_uint16_1, fnname: "mod_uint16_1", in: 0, want: 0},
+ test_uint16{fn: mod_1_uint16, fnname: "mod_1_uint16", in: 1, want: 0},
+ test_uint16{fn: mod_uint16_1, fnname: "mod_uint16_1", in: 1, want: 0},
+ test_uint16{fn: mod_1_uint16, fnname: "mod_1_uint16", in: 65535, want: 1},
+ test_uint16{fn: mod_uint16_1, fnname: "mod_uint16_1", in: 65535, want: 0},
+ test_uint16{fn: mod_uint16_65535, fnname: "mod_uint16_65535", in: 0, want: 0},
+ test_uint16{fn: mod_65535_uint16, fnname: "mod_65535_uint16", in: 1, want: 0},
+ test_uint16{fn: mod_uint16_65535, fnname: "mod_uint16_65535", in: 1, want: 1},
+ test_uint16{fn: mod_65535_uint16, fnname: "mod_65535_uint16", in: 65535, want: 0},
+ test_uint16{fn: mod_uint16_65535, fnname: "mod_uint16_65535", in: 65535, want: 0},
+ test_uint16{fn: and_0_uint16, fnname: "and_0_uint16", in: 0, want: 0},
+ test_uint16{fn: and_uint16_0, fnname: "and_uint16_0", in: 0, want: 0},
+ test_uint16{fn: and_0_uint16, fnname: "and_0_uint16", in: 1, want: 0},
+ test_uint16{fn: and_uint16_0, fnname: "and_uint16_0", in: 1, want: 0},
+ test_uint16{fn: and_0_uint16, fnname: "and_0_uint16", in: 65535, want: 0},
+ test_uint16{fn: and_uint16_0, fnname: "and_uint16_0", in: 65535, want: 0},
+ test_uint16{fn: and_1_uint16, fnname: "and_1_uint16", in: 0, want: 0},
+ test_uint16{fn: and_uint16_1, fnname: "and_uint16_1", in: 0, want: 0},
+ test_uint16{fn: and_1_uint16, fnname: "and_1_uint16", in: 1, want: 1},
+ test_uint16{fn: and_uint16_1, fnname: "and_uint16_1", in: 1, want: 1},
+ test_uint16{fn: and_1_uint16, fnname: "and_1_uint16", in: 65535, want: 1},
+ test_uint16{fn: and_uint16_1, fnname: "and_uint16_1", in: 65535, want: 1},
+ test_uint16{fn: and_65535_uint16, fnname: "and_65535_uint16", in: 0, want: 0},
+ test_uint16{fn: and_uint16_65535, fnname: "and_uint16_65535", in: 0, want: 0},
+ test_uint16{fn: and_65535_uint16, fnname: "and_65535_uint16", in: 1, want: 1},
+ test_uint16{fn: and_uint16_65535, fnname: "and_uint16_65535", in: 1, want: 1},
+ test_uint16{fn: and_65535_uint16, fnname: "and_65535_uint16", in: 65535, want: 65535},
+ test_uint16{fn: and_uint16_65535, fnname: "and_uint16_65535", in: 65535, want: 65535},
+ test_uint16{fn: or_0_uint16, fnname: "or_0_uint16", in: 0, want: 0},
+ test_uint16{fn: or_uint16_0, fnname: "or_uint16_0", in: 0, want: 0},
+ test_uint16{fn: or_0_uint16, fnname: "or_0_uint16", in: 1, want: 1},
+ test_uint16{fn: or_uint16_0, fnname: "or_uint16_0", in: 1, want: 1},
+ test_uint16{fn: or_0_uint16, fnname: "or_0_uint16", in: 65535, want: 65535},
+ test_uint16{fn: or_uint16_0, fnname: "or_uint16_0", in: 65535, want: 65535},
+ test_uint16{fn: or_1_uint16, fnname: "or_1_uint16", in: 0, want: 1},
+ test_uint16{fn: or_uint16_1, fnname: "or_uint16_1", in: 0, want: 1},
+ test_uint16{fn: or_1_uint16, fnname: "or_1_uint16", in: 1, want: 1},
+ test_uint16{fn: or_uint16_1, fnname: "or_uint16_1", in: 1, want: 1},
+ test_uint16{fn: or_1_uint16, fnname: "or_1_uint16", in: 65535, want: 65535},
+ test_uint16{fn: or_uint16_1, fnname: "or_uint16_1", in: 65535, want: 65535},
+ test_uint16{fn: or_65535_uint16, fnname: "or_65535_uint16", in: 0, want: 65535},
+ test_uint16{fn: or_uint16_65535, fnname: "or_uint16_65535", in: 0, want: 65535},
+ test_uint16{fn: or_65535_uint16, fnname: "or_65535_uint16", in: 1, want: 65535},
+ test_uint16{fn: or_uint16_65535, fnname: "or_uint16_65535", in: 1, want: 65535},
+ test_uint16{fn: or_65535_uint16, fnname: "or_65535_uint16", in: 65535, want: 65535},
+ test_uint16{fn: or_uint16_65535, fnname: "or_uint16_65535", in: 65535, want: 65535},
+ test_uint16{fn: xor_0_uint16, fnname: "xor_0_uint16", in: 0, want: 0},
+ test_uint16{fn: xor_uint16_0, fnname: "xor_uint16_0", in: 0, want: 0},
+ test_uint16{fn: xor_0_uint16, fnname: "xor_0_uint16", in: 1, want: 1},
+ test_uint16{fn: xor_uint16_0, fnname: "xor_uint16_0", in: 1, want: 1},
+ test_uint16{fn: xor_0_uint16, fnname: "xor_0_uint16", in: 65535, want: 65535},
+ test_uint16{fn: xor_uint16_0, fnname: "xor_uint16_0", in: 65535, want: 65535},
+ test_uint16{fn: xor_1_uint16, fnname: "xor_1_uint16", in: 0, want: 1},
+ test_uint16{fn: xor_uint16_1, fnname: "xor_uint16_1", in: 0, want: 1},
+ test_uint16{fn: xor_1_uint16, fnname: "xor_1_uint16", in: 1, want: 0},
+ test_uint16{fn: xor_uint16_1, fnname: "xor_uint16_1", in: 1, want: 0},
+ test_uint16{fn: xor_1_uint16, fnname: "xor_1_uint16", in: 65535, want: 65534},
+ test_uint16{fn: xor_uint16_1, fnname: "xor_uint16_1", in: 65535, want: 65534},
+ test_uint16{fn: xor_65535_uint16, fnname: "xor_65535_uint16", in: 0, want: 65535},
+ test_uint16{fn: xor_uint16_65535, fnname: "xor_uint16_65535", in: 0, want: 65535},
+ test_uint16{fn: xor_65535_uint16, fnname: "xor_65535_uint16", in: 1, want: 65534},
+ test_uint16{fn: xor_uint16_65535, fnname: "xor_uint16_65535", in: 1, want: 65534},
+ test_uint16{fn: xor_65535_uint16, fnname: "xor_65535_uint16", in: 65535, want: 0},
+ test_uint16{fn: xor_uint16_65535, fnname: "xor_uint16_65535", in: 65535, want: 0}}
+
+type test_int16 struct {
+ fn func(int16) int16
+ fnname string
+ in int16
+ want int16
+}
+
+var tests_int16 = []test_int16{
+
+ test_int16{fn: add_Neg32768_int16, fnname: "add_Neg32768_int16", in: -32768, want: 0},
+ test_int16{fn: add_int16_Neg32768, fnname: "add_int16_Neg32768", in: -32768, want: 0},
+ test_int16{fn: add_Neg32768_int16, fnname: "add_Neg32768_int16", in: -32767, want: 1},
+ test_int16{fn: add_int16_Neg32768, fnname: "add_int16_Neg32768", in: -32767, want: 1},
+ test_int16{fn: add_Neg32768_int16, fnname: "add_Neg32768_int16", in: -1, want: 32767},
+ test_int16{fn: add_int16_Neg32768, fnname: "add_int16_Neg32768", in: -1, want: 32767},
+ test_int16{fn: add_Neg32768_int16, fnname: "add_Neg32768_int16", in: 0, want: -32768},
+ test_int16{fn: add_int16_Neg32768, fnname: "add_int16_Neg32768", in: 0, want: -32768},
+ test_int16{fn: add_Neg32768_int16, fnname: "add_Neg32768_int16", in: 1, want: -32767},
+ test_int16{fn: add_int16_Neg32768, fnname: "add_int16_Neg32768", in: 1, want: -32767},
+ test_int16{fn: add_Neg32768_int16, fnname: "add_Neg32768_int16", in: 32766, want: -2},
+ test_int16{fn: add_int16_Neg32768, fnname: "add_int16_Neg32768", in: 32766, want: -2},
+ test_int16{fn: add_Neg32768_int16, fnname: "add_Neg32768_int16", in: 32767, want: -1},
+ test_int16{fn: add_int16_Neg32768, fnname: "add_int16_Neg32768", in: 32767, want: -1},
+ test_int16{fn: add_Neg32767_int16, fnname: "add_Neg32767_int16", in: -32768, want: 1},
+ test_int16{fn: add_int16_Neg32767, fnname: "add_int16_Neg32767", in: -32768, want: 1},
+ test_int16{fn: add_Neg32767_int16, fnname: "add_Neg32767_int16", in: -32767, want: 2},
+ test_int16{fn: add_int16_Neg32767, fnname: "add_int16_Neg32767", in: -32767, want: 2},
+ test_int16{fn: add_Neg32767_int16, fnname: "add_Neg32767_int16", in: -1, want: -32768},
+ test_int16{fn: add_int16_Neg32767, fnname: "add_int16_Neg32767", in: -1, want: -32768},
+ test_int16{fn: add_Neg32767_int16, fnname: "add_Neg32767_int16", in: 0, want: -32767},
+ test_int16{fn: add_int16_Neg32767, fnname: "add_int16_Neg32767", in: 0, want: -32767},
+ test_int16{fn: add_Neg32767_int16, fnname: "add_Neg32767_int16", in: 1, want: -32766},
+ test_int16{fn: add_int16_Neg32767, fnname: "add_int16_Neg32767", in: 1, want: -32766},
+ test_int16{fn: add_Neg32767_int16, fnname: "add_Neg32767_int16", in: 32766, want: -1},
+ test_int16{fn: add_int16_Neg32767, fnname: "add_int16_Neg32767", in: 32766, want: -1},
+ test_int16{fn: add_Neg32767_int16, fnname: "add_Neg32767_int16", in: 32767, want: 0},
+ test_int16{fn: add_int16_Neg32767, fnname: "add_int16_Neg32767", in: 32767, want: 0},
+ test_int16{fn: add_Neg1_int16, fnname: "add_Neg1_int16", in: -32768, want: 32767},
+ test_int16{fn: add_int16_Neg1, fnname: "add_int16_Neg1", in: -32768, want: 32767},
+ test_int16{fn: add_Neg1_int16, fnname: "add_Neg1_int16", in: -32767, want: -32768},
+ test_int16{fn: add_int16_Neg1, fnname: "add_int16_Neg1", in: -32767, want: -32768},
+ test_int16{fn: add_Neg1_int16, fnname: "add_Neg1_int16", in: -1, want: -2},
+ test_int16{fn: add_int16_Neg1, fnname: "add_int16_Neg1", in: -1, want: -2},
+ test_int16{fn: add_Neg1_int16, fnname: "add_Neg1_int16", in: 0, want: -1},
+ test_int16{fn: add_int16_Neg1, fnname: "add_int16_Neg1", in: 0, want: -1},
+ test_int16{fn: add_Neg1_int16, fnname: "add_Neg1_int16", in: 1, want: 0},
+ test_int16{fn: add_int16_Neg1, fnname: "add_int16_Neg1", in: 1, want: 0},
+ test_int16{fn: add_Neg1_int16, fnname: "add_Neg1_int16", in: 32766, want: 32765},
+ test_int16{fn: add_int16_Neg1, fnname: "add_int16_Neg1", in: 32766, want: 32765},
+ test_int16{fn: add_Neg1_int16, fnname: "add_Neg1_int16", in: 32767, want: 32766},
+ test_int16{fn: add_int16_Neg1, fnname: "add_int16_Neg1", in: 32767, want: 32766},
+ test_int16{fn: add_0_int16, fnname: "add_0_int16", in: -32768, want: -32768},
+ test_int16{fn: add_int16_0, fnname: "add_int16_0", in: -32768, want: -32768},
+ test_int16{fn: add_0_int16, fnname: "add_0_int16", in: -32767, want: -32767},
+ test_int16{fn: add_int16_0, fnname: "add_int16_0", in: -32767, want: -32767},
+ test_int16{fn: add_0_int16, fnname: "add_0_int16", in: -1, want: -1},
+ test_int16{fn: add_int16_0, fnname: "add_int16_0", in: -1, want: -1},
+ test_int16{fn: add_0_int16, fnname: "add_0_int16", in: 0, want: 0},
+ test_int16{fn: add_int16_0, fnname: "add_int16_0", in: 0, want: 0},
+ test_int16{fn: add_0_int16, fnname: "add_0_int16", in: 1, want: 1},
+ test_int16{fn: add_int16_0, fnname: "add_int16_0", in: 1, want: 1},
+ test_int16{fn: add_0_int16, fnname: "add_0_int16", in: 32766, want: 32766},
+ test_int16{fn: add_int16_0, fnname: "add_int16_0", in: 32766, want: 32766},
+ test_int16{fn: add_0_int16, fnname: "add_0_int16", in: 32767, want: 32767},
+ test_int16{fn: add_int16_0, fnname: "add_int16_0", in: 32767, want: 32767},
+ test_int16{fn: add_1_int16, fnname: "add_1_int16", in: -32768, want: -32767},
+ test_int16{fn: add_int16_1, fnname: "add_int16_1", in: -32768, want: -32767},
+ test_int16{fn: add_1_int16, fnname: "add_1_int16", in: -32767, want: -32766},
+ test_int16{fn: add_int16_1, fnname: "add_int16_1", in: -32767, want: -32766},
+ test_int16{fn: add_1_int16, fnname: "add_1_int16", in: -1, want: 0},
+ test_int16{fn: add_int16_1, fnname: "add_int16_1", in: -1, want: 0},
+ test_int16{fn: add_1_int16, fnname: "add_1_int16", in: 0, want: 1},
+ test_int16{fn: add_int16_1, fnname: "add_int16_1", in: 0, want: 1},
+ test_int16{fn: add_1_int16, fnname: "add_1_int16", in: 1, want: 2},
+ test_int16{fn: add_int16_1, fnname: "add_int16_1", in: 1, want: 2},
+ test_int16{fn: add_1_int16, fnname: "add_1_int16", in: 32766, want: 32767},
+ test_int16{fn: add_int16_1, fnname: "add_int16_1", in: 32766, want: 32767},
+ test_int16{fn: add_1_int16, fnname: "add_1_int16", in: 32767, want: -32768},
+ test_int16{fn: add_int16_1, fnname: "add_int16_1", in: 32767, want: -32768},
+ test_int16{fn: add_32766_int16, fnname: "add_32766_int16", in: -32768, want: -2},
+ test_int16{fn: add_int16_32766, fnname: "add_int16_32766", in: -32768, want: -2},
+ test_int16{fn: add_32766_int16, fnname: "add_32766_int16", in: -32767, want: -1},
+ test_int16{fn: add_int16_32766, fnname: "add_int16_32766", in: -32767, want: -1},
+ test_int16{fn: add_32766_int16, fnname: "add_32766_int16", in: -1, want: 32765},
+ test_int16{fn: add_int16_32766, fnname: "add_int16_32766", in: -1, want: 32765},
+ test_int16{fn: add_32766_int16, fnname: "add_32766_int16", in: 0, want: 32766},
+ test_int16{fn: add_int16_32766, fnname: "add_int16_32766", in: 0, want: 32766},
+ test_int16{fn: add_32766_int16, fnname: "add_32766_int16", in: 1, want: 32767},
+ test_int16{fn: add_int16_32766, fnname: "add_int16_32766", in: 1, want: 32767},
+ test_int16{fn: add_32766_int16, fnname: "add_32766_int16", in: 32766, want: -4},
+ test_int16{fn: add_int16_32766, fnname: "add_int16_32766", in: 32766, want: -4},
+ test_int16{fn: add_32766_int16, fnname: "add_32766_int16", in: 32767, want: -3},
+ test_int16{fn: add_int16_32766, fnname: "add_int16_32766", in: 32767, want: -3},
+ test_int16{fn: add_32767_int16, fnname: "add_32767_int16", in: -32768, want: -1},
+ test_int16{fn: add_int16_32767, fnname: "add_int16_32767", in: -32768, want: -1},
+ test_int16{fn: add_32767_int16, fnname: "add_32767_int16", in: -32767, want: 0},
+ test_int16{fn: add_int16_32767, fnname: "add_int16_32767", in: -32767, want: 0},
+ test_int16{fn: add_32767_int16, fnname: "add_32767_int16", in: -1, want: 32766},
+ test_int16{fn: add_int16_32767, fnname: "add_int16_32767", in: -1, want: 32766},
+ test_int16{fn: add_32767_int16, fnname: "add_32767_int16", in: 0, want: 32767},
+ test_int16{fn: add_int16_32767, fnname: "add_int16_32767", in: 0, want: 32767},
+ test_int16{fn: add_32767_int16, fnname: "add_32767_int16", in: 1, want: -32768},
+ test_int16{fn: add_int16_32767, fnname: "add_int16_32767", in: 1, want: -32768},
+ test_int16{fn: add_32767_int16, fnname: "add_32767_int16", in: 32766, want: -3},
+ test_int16{fn: add_int16_32767, fnname: "add_int16_32767", in: 32766, want: -3},
+ test_int16{fn: add_32767_int16, fnname: "add_32767_int16", in: 32767, want: -2},
+ test_int16{fn: add_int16_32767, fnname: "add_int16_32767", in: 32767, want: -2},
+ test_int16{fn: sub_Neg32768_int16, fnname: "sub_Neg32768_int16", in: -32768, want: 0},
+ test_int16{fn: sub_int16_Neg32768, fnname: "sub_int16_Neg32768", in: -32768, want: 0},
+ test_int16{fn: sub_Neg32768_int16, fnname: "sub_Neg32768_int16", in: -32767, want: -1},
+ test_int16{fn: sub_int16_Neg32768, fnname: "sub_int16_Neg32768", in: -32767, want: 1},
+ test_int16{fn: sub_Neg32768_int16, fnname: "sub_Neg32768_int16", in: -1, want: -32767},
+ test_int16{fn: sub_int16_Neg32768, fnname: "sub_int16_Neg32768", in: -1, want: 32767},
+ test_int16{fn: sub_Neg32768_int16, fnname: "sub_Neg32768_int16", in: 0, want: -32768},
+ test_int16{fn: sub_int16_Neg32768, fnname: "sub_int16_Neg32768", in: 0, want: -32768},
+ test_int16{fn: sub_Neg32768_int16, fnname: "sub_Neg32768_int16", in: 1, want: 32767},
+ test_int16{fn: sub_int16_Neg32768, fnname: "sub_int16_Neg32768", in: 1, want: -32767},
+ test_int16{fn: sub_Neg32768_int16, fnname: "sub_Neg32768_int16", in: 32766, want: 2},
+ test_int16{fn: sub_int16_Neg32768, fnname: "sub_int16_Neg32768", in: 32766, want: -2},
+ test_int16{fn: sub_Neg32768_int16, fnname: "sub_Neg32768_int16", in: 32767, want: 1},
+ test_int16{fn: sub_int16_Neg32768, fnname: "sub_int16_Neg32768", in: 32767, want: -1},
+ test_int16{fn: sub_Neg32767_int16, fnname: "sub_Neg32767_int16", in: -32768, want: 1},
+ test_int16{fn: sub_int16_Neg32767, fnname: "sub_int16_Neg32767", in: -32768, want: -1},
+ test_int16{fn: sub_Neg32767_int16, fnname: "sub_Neg32767_int16", in: -32767, want: 0},
+ test_int16{fn: sub_int16_Neg32767, fnname: "sub_int16_Neg32767", in: -32767, want: 0},
+ test_int16{fn: sub_Neg32767_int16, fnname: "sub_Neg32767_int16", in: -1, want: -32766},
+ test_int16{fn: sub_int16_Neg32767, fnname: "sub_int16_Neg32767", in: -1, want: 32766},
+ test_int16{fn: sub_Neg32767_int16, fnname: "sub_Neg32767_int16", in: 0, want: -32767},
+ test_int16{fn: sub_int16_Neg32767, fnname: "sub_int16_Neg32767", in: 0, want: 32767},
+ test_int16{fn: sub_Neg32767_int16, fnname: "sub_Neg32767_int16", in: 1, want: -32768},
+ test_int16{fn: sub_int16_Neg32767, fnname: "sub_int16_Neg32767", in: 1, want: -32768},
+ test_int16{fn: sub_Neg32767_int16, fnname: "sub_Neg32767_int16", in: 32766, want: 3},
+ test_int16{fn: sub_int16_Neg32767, fnname: "sub_int16_Neg32767", in: 32766, want: -3},
+ test_int16{fn: sub_Neg32767_int16, fnname: "sub_Neg32767_int16", in: 32767, want: 2},
+ test_int16{fn: sub_int16_Neg32767, fnname: "sub_int16_Neg32767", in: 32767, want: -2},
+ test_int16{fn: sub_Neg1_int16, fnname: "sub_Neg1_int16", in: -32768, want: 32767},
+ test_int16{fn: sub_int16_Neg1, fnname: "sub_int16_Neg1", in: -32768, want: -32767},
+ test_int16{fn: sub_Neg1_int16, fnname: "sub_Neg1_int16", in: -32767, want: 32766},
+ test_int16{fn: sub_int16_Neg1, fnname: "sub_int16_Neg1", in: -32767, want: -32766},
+ test_int16{fn: sub_Neg1_int16, fnname: "sub_Neg1_int16", in: -1, want: 0},
+ test_int16{fn: sub_int16_Neg1, fnname: "sub_int16_Neg1", in: -1, want: 0},
+ test_int16{fn: sub_Neg1_int16, fnname: "sub_Neg1_int16", in: 0, want: -1},
+ test_int16{fn: sub_int16_Neg1, fnname: "sub_int16_Neg1", in: 0, want: 1},
+ test_int16{fn: sub_Neg1_int16, fnname: "sub_Neg1_int16", in: 1, want: -2},
+ test_int16{fn: sub_int16_Neg1, fnname: "sub_int16_Neg1", in: 1, want: 2},
+ test_int16{fn: sub_Neg1_int16, fnname: "sub_Neg1_int16", in: 32766, want: -32767},
+ test_int16{fn: sub_int16_Neg1, fnname: "sub_int16_Neg1", in: 32766, want: 32767},
+ test_int16{fn: sub_Neg1_int16, fnname: "sub_Neg1_int16", in: 32767, want: -32768},
+ test_int16{fn: sub_int16_Neg1, fnname: "sub_int16_Neg1", in: 32767, want: -32768},
+ test_int16{fn: sub_0_int16, fnname: "sub_0_int16", in: -32768, want: -32768},
+ test_int16{fn: sub_int16_0, fnname: "sub_int16_0", in: -32768, want: -32768},
+ test_int16{fn: sub_0_int16, fnname: "sub_0_int16", in: -32767, want: 32767},
+ test_int16{fn: sub_int16_0, fnname: "sub_int16_0", in: -32767, want: -32767},
+ test_int16{fn: sub_0_int16, fnname: "sub_0_int16", in: -1, want: 1},
+ test_int16{fn: sub_int16_0, fnname: "sub_int16_0", in: -1, want: -1},
+ test_int16{fn: sub_0_int16, fnname: "sub_0_int16", in: 0, want: 0},
+ test_int16{fn: sub_int16_0, fnname: "sub_int16_0", in: 0, want: 0},
+ test_int16{fn: sub_0_int16, fnname: "sub_0_int16", in: 1, want: -1},
+ test_int16{fn: sub_int16_0, fnname: "sub_int16_0", in: 1, want: 1},
+ test_int16{fn: sub_0_int16, fnname: "sub_0_int16", in: 32766, want: -32766},
+ test_int16{fn: sub_int16_0, fnname: "sub_int16_0", in: 32766, want: 32766},
+ test_int16{fn: sub_0_int16, fnname: "sub_0_int16", in: 32767, want: -32767},
+ test_int16{fn: sub_int16_0, fnname: "sub_int16_0", in: 32767, want: 32767},
+ test_int16{fn: sub_1_int16, fnname: "sub_1_int16", in: -32768, want: -32767},
+ test_int16{fn: sub_int16_1, fnname: "sub_int16_1", in: -32768, want: 32767},
+ test_int16{fn: sub_1_int16, fnname: "sub_1_int16", in: -32767, want: -32768},
+ test_int16{fn: sub_int16_1, fnname: "sub_int16_1", in: -32767, want: -32768},
+ test_int16{fn: sub_1_int16, fnname: "sub_1_int16", in: -1, want: 2},
+ test_int16{fn: sub_int16_1, fnname: "sub_int16_1", in: -1, want: -2},
+ test_int16{fn: sub_1_int16, fnname: "sub_1_int16", in: 0, want: 1},
+ test_int16{fn: sub_int16_1, fnname: "sub_int16_1", in: 0, want: -1},
+ test_int16{fn: sub_1_int16, fnname: "sub_1_int16", in: 1, want: 0},
+ test_int16{fn: sub_int16_1, fnname: "sub_int16_1", in: 1, want: 0},
+ test_int16{fn: sub_1_int16, fnname: "sub_1_int16", in: 32766, want: -32765},
+ test_int16{fn: sub_int16_1, fnname: "sub_int16_1", in: 32766, want: 32765},
+ test_int16{fn: sub_1_int16, fnname: "sub_1_int16", in: 32767, want: -32766},
+ test_int16{fn: sub_int16_1, fnname: "sub_int16_1", in: 32767, want: 32766},
+ test_int16{fn: sub_32766_int16, fnname: "sub_32766_int16", in: -32768, want: -2},
+ test_int16{fn: sub_int16_32766, fnname: "sub_int16_32766", in: -32768, want: 2},
+ test_int16{fn: sub_32766_int16, fnname: "sub_32766_int16", in: -32767, want: -3},
+ test_int16{fn: sub_int16_32766, fnname: "sub_int16_32766", in: -32767, want: 3},
+ test_int16{fn: sub_32766_int16, fnname: "sub_32766_int16", in: -1, want: 32767},
+ test_int16{fn: sub_int16_32766, fnname: "sub_int16_32766", in: -1, want: -32767},
+ test_int16{fn: sub_32766_int16, fnname: "sub_32766_int16", in: 0, want: 32766},
+ test_int16{fn: sub_int16_32766, fnname: "sub_int16_32766", in: 0, want: -32766},
+ test_int16{fn: sub_32766_int16, fnname: "sub_32766_int16", in: 1, want: 32765},
+ test_int16{fn: sub_int16_32766, fnname: "sub_int16_32766", in: 1, want: -32765},
+ test_int16{fn: sub_32766_int16, fnname: "sub_32766_int16", in: 32766, want: 0},
+ test_int16{fn: sub_int16_32766, fnname: "sub_int16_32766", in: 32766, want: 0},
+ test_int16{fn: sub_32766_int16, fnname: "sub_32766_int16", in: 32767, want: -1},
+ test_int16{fn: sub_int16_32766, fnname: "sub_int16_32766", in: 32767, want: 1},
+ test_int16{fn: sub_32767_int16, fnname: "sub_32767_int16", in: -32768, want: -1},
+ test_int16{fn: sub_int16_32767, fnname: "sub_int16_32767", in: -32768, want: 1},
+ test_int16{fn: sub_32767_int16, fnname: "sub_32767_int16", in: -32767, want: -2},
+ test_int16{fn: sub_int16_32767, fnname: "sub_int16_32767", in: -32767, want: 2},
+ test_int16{fn: sub_32767_int16, fnname: "sub_32767_int16", in: -1, want: -32768},
+ test_int16{fn: sub_int16_32767, fnname: "sub_int16_32767", in: -1, want: -32768},
+ test_int16{fn: sub_32767_int16, fnname: "sub_32767_int16", in: 0, want: 32767},
+ test_int16{fn: sub_int16_32767, fnname: "sub_int16_32767", in: 0, want: -32767},
+ test_int16{fn: sub_32767_int16, fnname: "sub_32767_int16", in: 1, want: 32766},
+ test_int16{fn: sub_int16_32767, fnname: "sub_int16_32767", in: 1, want: -32766},
+ test_int16{fn: sub_32767_int16, fnname: "sub_32767_int16", in: 32766, want: 1},
+ test_int16{fn: sub_int16_32767, fnname: "sub_int16_32767", in: 32766, want: -1},
+ test_int16{fn: sub_32767_int16, fnname: "sub_32767_int16", in: 32767, want: 0},
+ test_int16{fn: sub_int16_32767, fnname: "sub_int16_32767", in: 32767, want: 0},
+ test_int16{fn: div_Neg32768_int16, fnname: "div_Neg32768_int16", in: -32768, want: 1},
+ test_int16{fn: div_int16_Neg32768, fnname: "div_int16_Neg32768", in: -32768, want: 1},
+ test_int16{fn: div_Neg32768_int16, fnname: "div_Neg32768_int16", in: -32767, want: 1},
+ test_int16{fn: div_int16_Neg32768, fnname: "div_int16_Neg32768", in: -32767, want: 0},
+ test_int16{fn: div_Neg32768_int16, fnname: "div_Neg32768_int16", in: -1, want: -32768},
+ test_int16{fn: div_int16_Neg32768, fnname: "div_int16_Neg32768", in: -1, want: 0},
+ test_int16{fn: div_int16_Neg32768, fnname: "div_int16_Neg32768", in: 0, want: 0},
+ test_int16{fn: div_Neg32768_int16, fnname: "div_Neg32768_int16", in: 1, want: -32768},
+ test_int16{fn: div_int16_Neg32768, fnname: "div_int16_Neg32768", in: 1, want: 0},
+ test_int16{fn: div_Neg32768_int16, fnname: "div_Neg32768_int16", in: 32766, want: -1},
+ test_int16{fn: div_int16_Neg32768, fnname: "div_int16_Neg32768", in: 32766, want: 0},
+ test_int16{fn: div_Neg32768_int16, fnname: "div_Neg32768_int16", in: 32767, want: -1},
+ test_int16{fn: div_int16_Neg32768, fnname: "div_int16_Neg32768", in: 32767, want: 0},
+ test_int16{fn: div_Neg32767_int16, fnname: "div_Neg32767_int16", in: -32768, want: 0},
+ test_int16{fn: div_int16_Neg32767, fnname: "div_int16_Neg32767", in: -32768, want: 1},
+ test_int16{fn: div_Neg32767_int16, fnname: "div_Neg32767_int16", in: -32767, want: 1},
+ test_int16{fn: div_int16_Neg32767, fnname: "div_int16_Neg32767", in: -32767, want: 1},
+ test_int16{fn: div_Neg32767_int16, fnname: "div_Neg32767_int16", in: -1, want: 32767},
+ test_int16{fn: div_int16_Neg32767, fnname: "div_int16_Neg32767", in: -1, want: 0},
+ test_int16{fn: div_int16_Neg32767, fnname: "div_int16_Neg32767", in: 0, want: 0},
+ test_int16{fn: div_Neg32767_int16, fnname: "div_Neg32767_int16", in: 1, want: -32767},
+ test_int16{fn: div_int16_Neg32767, fnname: "div_int16_Neg32767", in: 1, want: 0},
+ test_int16{fn: div_Neg32767_int16, fnname: "div_Neg32767_int16", in: 32766, want: -1},
+ test_int16{fn: div_int16_Neg32767, fnname: "div_int16_Neg32767", in: 32766, want: 0},
+ test_int16{fn: div_Neg32767_int16, fnname: "div_Neg32767_int16", in: 32767, want: -1},
+ test_int16{fn: div_int16_Neg32767, fnname: "div_int16_Neg32767", in: 32767, want: -1},
+ test_int16{fn: div_Neg1_int16, fnname: "div_Neg1_int16", in: -32768, want: 0},
+ test_int16{fn: div_int16_Neg1, fnname: "div_int16_Neg1", in: -32768, want: -32768},
+ test_int16{fn: div_Neg1_int16, fnname: "div_Neg1_int16", in: -32767, want: 0},
+ test_int16{fn: div_int16_Neg1, fnname: "div_int16_Neg1", in: -32767, want: 32767},
+ test_int16{fn: div_Neg1_int16, fnname: "div_Neg1_int16", in: -1, want: 1},
+ test_int16{fn: div_int16_Neg1, fnname: "div_int16_Neg1", in: -1, want: 1},
+ test_int16{fn: div_int16_Neg1, fnname: "div_int16_Neg1", in: 0, want: 0},
+ test_int16{fn: div_Neg1_int16, fnname: "div_Neg1_int16", in: 1, want: -1},
+ test_int16{fn: div_int16_Neg1, fnname: "div_int16_Neg1", in: 1, want: -1},
+ test_int16{fn: div_Neg1_int16, fnname: "div_Neg1_int16", in: 32766, want: 0},
+ test_int16{fn: div_int16_Neg1, fnname: "div_int16_Neg1", in: 32766, want: -32766},
+ test_int16{fn: div_Neg1_int16, fnname: "div_Neg1_int16", in: 32767, want: 0},
+ test_int16{fn: div_int16_Neg1, fnname: "div_int16_Neg1", in: 32767, want: -32767},
+ test_int16{fn: div_0_int16, fnname: "div_0_int16", in: -32768, want: 0},
+ test_int16{fn: div_0_int16, fnname: "div_0_int16", in: -32767, want: 0},
+ test_int16{fn: div_0_int16, fnname: "div_0_int16", in: -1, want: 0},
+ test_int16{fn: div_0_int16, fnname: "div_0_int16", in: 1, want: 0},
+ test_int16{fn: div_0_int16, fnname: "div_0_int16", in: 32766, want: 0},
+ test_int16{fn: div_0_int16, fnname: "div_0_int16", in: 32767, want: 0},
+ test_int16{fn: div_1_int16, fnname: "div_1_int16", in: -32768, want: 0},
+ test_int16{fn: div_int16_1, fnname: "div_int16_1", in: -32768, want: -32768},
+ test_int16{fn: div_1_int16, fnname: "div_1_int16", in: -32767, want: 0},
+ test_int16{fn: div_int16_1, fnname: "div_int16_1", in: -32767, want: -32767},
+ test_int16{fn: div_1_int16, fnname: "div_1_int16", in: -1, want: -1},
+ test_int16{fn: div_int16_1, fnname: "div_int16_1", in: -1, want: -1},
+ test_int16{fn: div_int16_1, fnname: "div_int16_1", in: 0, want: 0},
+ test_int16{fn: div_1_int16, fnname: "div_1_int16", in: 1, want: 1},
+ test_int16{fn: div_int16_1, fnname: "div_int16_1", in: 1, want: 1},
+ test_int16{fn: div_1_int16, fnname: "div_1_int16", in: 32766, want: 0},
+ test_int16{fn: div_int16_1, fnname: "div_int16_1", in: 32766, want: 32766},
+ test_int16{fn: div_1_int16, fnname: "div_1_int16", in: 32767, want: 0},
+ test_int16{fn: div_int16_1, fnname: "div_int16_1", in: 32767, want: 32767},
+ test_int16{fn: div_32766_int16, fnname: "div_32766_int16", in: -32768, want: 0},
+ test_int16{fn: div_int16_32766, fnname: "div_int16_32766", in: -32768, want: -1},
+ test_int16{fn: div_32766_int16, fnname: "div_32766_int16", in: -32767, want: 0},
+ test_int16{fn: div_int16_32766, fnname: "div_int16_32766", in: -32767, want: -1},
+ test_int16{fn: div_32766_int16, fnname: "div_32766_int16", in: -1, want: -32766},
+ test_int16{fn: div_int16_32766, fnname: "div_int16_32766", in: -1, want: 0},
+ test_int16{fn: div_int16_32766, fnname: "div_int16_32766", in: 0, want: 0},
+ test_int16{fn: div_32766_int16, fnname: "div_32766_int16", in: 1, want: 32766},
+ test_int16{fn: div_int16_32766, fnname: "div_int16_32766", in: 1, want: 0},
+ test_int16{fn: div_32766_int16, fnname: "div_32766_int16", in: 32766, want: 1},
+ test_int16{fn: div_int16_32766, fnname: "div_int16_32766", in: 32766, want: 1},
+ test_int16{fn: div_32766_int16, fnname: "div_32766_int16", in: 32767, want: 0},
+ test_int16{fn: div_int16_32766, fnname: "div_int16_32766", in: 32767, want: 1},
+ test_int16{fn: div_32767_int16, fnname: "div_32767_int16", in: -32768, want: 0},
+ test_int16{fn: div_int16_32767, fnname: "div_int16_32767", in: -32768, want: -1},
+ test_int16{fn: div_32767_int16, fnname: "div_32767_int16", in: -32767, want: -1},
+ test_int16{fn: div_int16_32767, fnname: "div_int16_32767", in: -32767, want: -1},
+ test_int16{fn: div_32767_int16, fnname: "div_32767_int16", in: -1, want: -32767},
+ test_int16{fn: div_int16_32767, fnname: "div_int16_32767", in: -1, want: 0},
+ test_int16{fn: div_int16_32767, fnname: "div_int16_32767", in: 0, want: 0},
+ test_int16{fn: div_32767_int16, fnname: "div_32767_int16", in: 1, want: 32767},
+ test_int16{fn: div_int16_32767, fnname: "div_int16_32767", in: 1, want: 0},
+ test_int16{fn: div_32767_int16, fnname: "div_32767_int16", in: 32766, want: 1},
+ test_int16{fn: div_int16_32767, fnname: "div_int16_32767", in: 32766, want: 0},
+ test_int16{fn: div_32767_int16, fnname: "div_32767_int16", in: 32767, want: 1},
+ test_int16{fn: div_int16_32767, fnname: "div_int16_32767", in: 32767, want: 1},
+ test_int16{fn: mul_Neg32768_int16, fnname: "mul_Neg32768_int16", in: -32768, want: 0},
+ test_int16{fn: mul_int16_Neg32768, fnname: "mul_int16_Neg32768", in: -32768, want: 0},
+ test_int16{fn: mul_Neg32768_int16, fnname: "mul_Neg32768_int16", in: -32767, want: -32768},
+ test_int16{fn: mul_int16_Neg32768, fnname: "mul_int16_Neg32768", in: -32767, want: -32768},
+ test_int16{fn: mul_Neg32768_int16, fnname: "mul_Neg32768_int16", in: -1, want: -32768},
+ test_int16{fn: mul_int16_Neg32768, fnname: "mul_int16_Neg32768", in: -1, want: -32768},
+ test_int16{fn: mul_Neg32768_int16, fnname: "mul_Neg32768_int16", in: 0, want: 0},
+ test_int16{fn: mul_int16_Neg32768, fnname: "mul_int16_Neg32768", in: 0, want: 0},
+ test_int16{fn: mul_Neg32768_int16, fnname: "mul_Neg32768_int16", in: 1, want: -32768},
+ test_int16{fn: mul_int16_Neg32768, fnname: "mul_int16_Neg32768", in: 1, want: -32768},
+ test_int16{fn: mul_Neg32768_int16, fnname: "mul_Neg32768_int16", in: 32766, want: 0},
+ test_int16{fn: mul_int16_Neg32768, fnname: "mul_int16_Neg32768", in: 32766, want: 0},
+ test_int16{fn: mul_Neg32768_int16, fnname: "mul_Neg32768_int16", in: 32767, want: -32768},
+ test_int16{fn: mul_int16_Neg32768, fnname: "mul_int16_Neg32768", in: 32767, want: -32768},
+ test_int16{fn: mul_Neg32767_int16, fnname: "mul_Neg32767_int16", in: -32768, want: -32768},
+ test_int16{fn: mul_int16_Neg32767, fnname: "mul_int16_Neg32767", in: -32768, want: -32768},
+ test_int16{fn: mul_Neg32767_int16, fnname: "mul_Neg32767_int16", in: -32767, want: 1},
+ test_int16{fn: mul_int16_Neg32767, fnname: "mul_int16_Neg32767", in: -32767, want: 1},
+ test_int16{fn: mul_Neg32767_int16, fnname: "mul_Neg32767_int16", in: -1, want: 32767},
+ test_int16{fn: mul_int16_Neg32767, fnname: "mul_int16_Neg32767", in: -1, want: 32767},
+ test_int16{fn: mul_Neg32767_int16, fnname: "mul_Neg32767_int16", in: 0, want: 0},
+ test_int16{fn: mul_int16_Neg32767, fnname: "mul_int16_Neg32767", in: 0, want: 0},
+ test_int16{fn: mul_Neg32767_int16, fnname: "mul_Neg32767_int16", in: 1, want: -32767},
+ test_int16{fn: mul_int16_Neg32767, fnname: "mul_int16_Neg32767", in: 1, want: -32767},
+ test_int16{fn: mul_Neg32767_int16, fnname: "mul_Neg32767_int16", in: 32766, want: 32766},
+ test_int16{fn: mul_int16_Neg32767, fnname: "mul_int16_Neg32767", in: 32766, want: 32766},
+ test_int16{fn: mul_Neg32767_int16, fnname: "mul_Neg32767_int16", in: 32767, want: -1},
+ test_int16{fn: mul_int16_Neg32767, fnname: "mul_int16_Neg32767", in: 32767, want: -1},
+ test_int16{fn: mul_Neg1_int16, fnname: "mul_Neg1_int16", in: -32768, want: -32768},
+ test_int16{fn: mul_int16_Neg1, fnname: "mul_int16_Neg1", in: -32768, want: -32768},
+ test_int16{fn: mul_Neg1_int16, fnname: "mul_Neg1_int16", in: -32767, want: 32767},
+ test_int16{fn: mul_int16_Neg1, fnname: "mul_int16_Neg1", in: -32767, want: 32767},
+ test_int16{fn: mul_Neg1_int16, fnname: "mul_Neg1_int16", in: -1, want: 1},
+ test_int16{fn: mul_int16_Neg1, fnname: "mul_int16_Neg1", in: -1, want: 1},
+ test_int16{fn: mul_Neg1_int16, fnname: "mul_Neg1_int16", in: 0, want: 0},
+ test_int16{fn: mul_int16_Neg1, fnname: "mul_int16_Neg1", in: 0, want: 0},
+ test_int16{fn: mul_Neg1_int16, fnname: "mul_Neg1_int16", in: 1, want: -1},
+ test_int16{fn: mul_int16_Neg1, fnname: "mul_int16_Neg1", in: 1, want: -1},
+ test_int16{fn: mul_Neg1_int16, fnname: "mul_Neg1_int16", in: 32766, want: -32766},
+ test_int16{fn: mul_int16_Neg1, fnname: "mul_int16_Neg1", in: 32766, want: -32766},
+ test_int16{fn: mul_Neg1_int16, fnname: "mul_Neg1_int16", in: 32767, want: -32767},
+ test_int16{fn: mul_int16_Neg1, fnname: "mul_int16_Neg1", in: 32767, want: -32767},
+ test_int16{fn: mul_0_int16, fnname: "mul_0_int16", in: -32768, want: 0},
+ test_int16{fn: mul_int16_0, fnname: "mul_int16_0", in: -32768, want: 0},
+ test_int16{fn: mul_0_int16, fnname: "mul_0_int16", in: -32767, want: 0},
+ test_int16{fn: mul_int16_0, fnname: "mul_int16_0", in: -32767, want: 0},
+ test_int16{fn: mul_0_int16, fnname: "mul_0_int16", in: -1, want: 0},
+ test_int16{fn: mul_int16_0, fnname: "mul_int16_0", in: -1, want: 0},
+ test_int16{fn: mul_0_int16, fnname: "mul_0_int16", in: 0, want: 0},
+ test_int16{fn: mul_int16_0, fnname: "mul_int16_0", in: 0, want: 0},
+ test_int16{fn: mul_0_int16, fnname: "mul_0_int16", in: 1, want: 0},
+ test_int16{fn: mul_int16_0, fnname: "mul_int16_0", in: 1, want: 0},
+ test_int16{fn: mul_0_int16, fnname: "mul_0_int16", in: 32766, want: 0},
+ test_int16{fn: mul_int16_0, fnname: "mul_int16_0", in: 32766, want: 0},
+ test_int16{fn: mul_0_int16, fnname: "mul_0_int16", in: 32767, want: 0},
+ test_int16{fn: mul_int16_0, fnname: "mul_int16_0", in: 32767, want: 0},
+ test_int16{fn: mul_1_int16, fnname: "mul_1_int16", in: -32768, want: -32768},
+ test_int16{fn: mul_int16_1, fnname: "mul_int16_1", in: -32768, want: -32768},
+ test_int16{fn: mul_1_int16, fnname: "mul_1_int16", in: -32767, want: -32767},
+ test_int16{fn: mul_int16_1, fnname: "mul_int16_1", in: -32767, want: -32767},
+ test_int16{fn: mul_1_int16, fnname: "mul_1_int16", in: -1, want: -1},
+ test_int16{fn: mul_int16_1, fnname: "mul_int16_1", in: -1, want: -1},
+ test_int16{fn: mul_1_int16, fnname: "mul_1_int16", in: 0, want: 0},
+ test_int16{fn: mul_int16_1, fnname: "mul_int16_1", in: 0, want: 0},
+ test_int16{fn: mul_1_int16, fnname: "mul_1_int16", in: 1, want: 1},
+ test_int16{fn: mul_int16_1, fnname: "mul_int16_1", in: 1, want: 1},
+ test_int16{fn: mul_1_int16, fnname: "mul_1_int16", in: 32766, want: 32766},
+ test_int16{fn: mul_int16_1, fnname: "mul_int16_1", in: 32766, want: 32766},
+ test_int16{fn: mul_1_int16, fnname: "mul_1_int16", in: 32767, want: 32767},
+ test_int16{fn: mul_int16_1, fnname: "mul_int16_1", in: 32767, want: 32767},
+ test_int16{fn: mul_32766_int16, fnname: "mul_32766_int16", in: -32768, want: 0},
+ test_int16{fn: mul_int16_32766, fnname: "mul_int16_32766", in: -32768, want: 0},
+ test_int16{fn: mul_32766_int16, fnname: "mul_32766_int16", in: -32767, want: 32766},
+ test_int16{fn: mul_int16_32766, fnname: "mul_int16_32766", in: -32767, want: 32766},
+ test_int16{fn: mul_32766_int16, fnname: "mul_32766_int16", in: -1, want: -32766},
+ test_int16{fn: mul_int16_32766, fnname: "mul_int16_32766", in: -1, want: -32766},
+ test_int16{fn: mul_32766_int16, fnname: "mul_32766_int16", in: 0, want: 0},
+ test_int16{fn: mul_int16_32766, fnname: "mul_int16_32766", in: 0, want: 0},
+ test_int16{fn: mul_32766_int16, fnname: "mul_32766_int16", in: 1, want: 32766},
+ test_int16{fn: mul_int16_32766, fnname: "mul_int16_32766", in: 1, want: 32766},
+ test_int16{fn: mul_32766_int16, fnname: "mul_32766_int16", in: 32766, want: 4},
+ test_int16{fn: mul_int16_32766, fnname: "mul_int16_32766", in: 32766, want: 4},
+ test_int16{fn: mul_32766_int16, fnname: "mul_32766_int16", in: 32767, want: -32766},
+ test_int16{fn: mul_int16_32766, fnname: "mul_int16_32766", in: 32767, want: -32766},
+ test_int16{fn: mul_32767_int16, fnname: "mul_32767_int16", in: -32768, want: -32768},
+ test_int16{fn: mul_int16_32767, fnname: "mul_int16_32767", in: -32768, want: -32768},
+ test_int16{fn: mul_32767_int16, fnname: "mul_32767_int16", in: -32767, want: -1},
+ test_int16{fn: mul_int16_32767, fnname: "mul_int16_32767", in: -32767, want: -1},
+ test_int16{fn: mul_32767_int16, fnname: "mul_32767_int16", in: -1, want: -32767},
+ test_int16{fn: mul_int16_32767, fnname: "mul_int16_32767", in: -1, want: -32767},
+ test_int16{fn: mul_32767_int16, fnname: "mul_32767_int16", in: 0, want: 0},
+ test_int16{fn: mul_int16_32767, fnname: "mul_int16_32767", in: 0, want: 0},
+ test_int16{fn: mul_32767_int16, fnname: "mul_32767_int16", in: 1, want: 32767},
+ test_int16{fn: mul_int16_32767, fnname: "mul_int16_32767", in: 1, want: 32767},
+ test_int16{fn: mul_32767_int16, fnname: "mul_32767_int16", in: 32766, want: -32766},
+ test_int16{fn: mul_int16_32767, fnname: "mul_int16_32767", in: 32766, want: -32766},
+ test_int16{fn: mul_32767_int16, fnname: "mul_32767_int16", in: 32767, want: 1},
+ test_int16{fn: mul_int16_32767, fnname: "mul_int16_32767", in: 32767, want: 1},
+ test_int16{fn: mod_Neg32768_int16, fnname: "mod_Neg32768_int16", in: -32768, want: 0},
+ test_int16{fn: mod_int16_Neg32768, fnname: "mod_int16_Neg32768", in: -32768, want: 0},
+ test_int16{fn: mod_Neg32768_int16, fnname: "mod_Neg32768_int16", in: -32767, want: -1},
+ test_int16{fn: mod_int16_Neg32768, fnname: "mod_int16_Neg32768", in: -32767, want: -32767},
+ test_int16{fn: mod_Neg32768_int16, fnname: "mod_Neg32768_int16", in: -1, want: 0},
+ test_int16{fn: mod_int16_Neg32768, fnname: "mod_int16_Neg32768", in: -1, want: -1},
+ test_int16{fn: mod_int16_Neg32768, fnname: "mod_int16_Neg32768", in: 0, want: 0},
+ test_int16{fn: mod_Neg32768_int16, fnname: "mod_Neg32768_int16", in: 1, want: 0},
+ test_int16{fn: mod_int16_Neg32768, fnname: "mod_int16_Neg32768", in: 1, want: 1},
+ test_int16{fn: mod_Neg32768_int16, fnname: "mod_Neg32768_int16", in: 32766, want: -2},
+ test_int16{fn: mod_int16_Neg32768, fnname: "mod_int16_Neg32768", in: 32766, want: 32766},
+ test_int16{fn: mod_Neg32768_int16, fnname: "mod_Neg32768_int16", in: 32767, want: -1},
+ test_int16{fn: mod_int16_Neg32768, fnname: "mod_int16_Neg32768", in: 32767, want: 32767},
+ test_int16{fn: mod_Neg32767_int16, fnname: "mod_Neg32767_int16", in: -32768, want: -32767},
+ test_int16{fn: mod_int16_Neg32767, fnname: "mod_int16_Neg32767", in: -32768, want: -1},
+ test_int16{fn: mod_Neg32767_int16, fnname: "mod_Neg32767_int16", in: -32767, want: 0},
+ test_int16{fn: mod_int16_Neg32767, fnname: "mod_int16_Neg32767", in: -32767, want: 0},
+ test_int16{fn: mod_Neg32767_int16, fnname: "mod_Neg32767_int16", in: -1, want: 0},
+ test_int16{fn: mod_int16_Neg32767, fnname: "mod_int16_Neg32767", in: -1, want: -1},
+ test_int16{fn: mod_int16_Neg32767, fnname: "mod_int16_Neg32767", in: 0, want: 0},
+ test_int16{fn: mod_Neg32767_int16, fnname: "mod_Neg32767_int16", in: 1, want: 0},
+ test_int16{fn: mod_int16_Neg32767, fnname: "mod_int16_Neg32767", in: 1, want: 1},
+ test_int16{fn: mod_Neg32767_int16, fnname: "mod_Neg32767_int16", in: 32766, want: -1},
+ test_int16{fn: mod_int16_Neg32767, fnname: "mod_int16_Neg32767", in: 32766, want: 32766},
+ test_int16{fn: mod_Neg32767_int16, fnname: "mod_Neg32767_int16", in: 32767, want: 0},
+ test_int16{fn: mod_int16_Neg32767, fnname: "mod_int16_Neg32767", in: 32767, want: 0},
+ test_int16{fn: mod_Neg1_int16, fnname: "mod_Neg1_int16", in: -32768, want: -1},
+ test_int16{fn: mod_int16_Neg1, fnname: "mod_int16_Neg1", in: -32768, want: 0},
+ test_int16{fn: mod_Neg1_int16, fnname: "mod_Neg1_int16", in: -32767, want: -1},
+ test_int16{fn: mod_int16_Neg1, fnname: "mod_int16_Neg1", in: -32767, want: 0},
+ test_int16{fn: mod_Neg1_int16, fnname: "mod_Neg1_int16", in: -1, want: 0},
+ test_int16{fn: mod_int16_Neg1, fnname: "mod_int16_Neg1", in: -1, want: 0},
+ test_int16{fn: mod_int16_Neg1, fnname: "mod_int16_Neg1", in: 0, want: 0},
+ test_int16{fn: mod_Neg1_int16, fnname: "mod_Neg1_int16", in: 1, want: 0},
+ test_int16{fn: mod_int16_Neg1, fnname: "mod_int16_Neg1", in: 1, want: 0},
+ test_int16{fn: mod_Neg1_int16, fnname: "mod_Neg1_int16", in: 32766, want: -1},
+ test_int16{fn: mod_int16_Neg1, fnname: "mod_int16_Neg1", in: 32766, want: 0},
+ test_int16{fn: mod_Neg1_int16, fnname: "mod_Neg1_int16", in: 32767, want: -1},
+ test_int16{fn: mod_int16_Neg1, fnname: "mod_int16_Neg1", in: 32767, want: 0},
+ test_int16{fn: mod_0_int16, fnname: "mod_0_int16", in: -32768, want: 0},
+ test_int16{fn: mod_0_int16, fnname: "mod_0_int16", in: -32767, want: 0},
+ test_int16{fn: mod_0_int16, fnname: "mod_0_int16", in: -1, want: 0},
+ test_int16{fn: mod_0_int16, fnname: "mod_0_int16", in: 1, want: 0},
+ test_int16{fn: mod_0_int16, fnname: "mod_0_int16", in: 32766, want: 0},
+ test_int16{fn: mod_0_int16, fnname: "mod_0_int16", in: 32767, want: 0},
+ test_int16{fn: mod_1_int16, fnname: "mod_1_int16", in: -32768, want: 1},
+ test_int16{fn: mod_int16_1, fnname: "mod_int16_1", in: -32768, want: 0},
+ test_int16{fn: mod_1_int16, fnname: "mod_1_int16", in: -32767, want: 1},
+ test_int16{fn: mod_int16_1, fnname: "mod_int16_1", in: -32767, want: 0},
+ test_int16{fn: mod_1_int16, fnname: "mod_1_int16", in: -1, want: 0},
+ test_int16{fn: mod_int16_1, fnname: "mod_int16_1", in: -1, want: 0},
+ test_int16{fn: mod_int16_1, fnname: "mod_int16_1", in: 0, want: 0},
+ test_int16{fn: mod_1_int16, fnname: "mod_1_int16", in: 1, want: 0},
+ test_int16{fn: mod_int16_1, fnname: "mod_int16_1", in: 1, want: 0},
+ test_int16{fn: mod_1_int16, fnname: "mod_1_int16", in: 32766, want: 1},
+ test_int16{fn: mod_int16_1, fnname: "mod_int16_1", in: 32766, want: 0},
+ test_int16{fn: mod_1_int16, fnname: "mod_1_int16", in: 32767, want: 1},
+ test_int16{fn: mod_int16_1, fnname: "mod_int16_1", in: 32767, want: 0},
+ test_int16{fn: mod_32766_int16, fnname: "mod_32766_int16", in: -32768, want: 32766},
+ test_int16{fn: mod_int16_32766, fnname: "mod_int16_32766", in: -32768, want: -2},
+ test_int16{fn: mod_32766_int16, fnname: "mod_32766_int16", in: -32767, want: 32766},
+ test_int16{fn: mod_int16_32766, fnname: "mod_int16_32766", in: -32767, want: -1},
+ test_int16{fn: mod_32766_int16, fnname: "mod_32766_int16", in: -1, want: 0},
+ test_int16{fn: mod_int16_32766, fnname: "mod_int16_32766", in: -1, want: -1},
+ test_int16{fn: mod_int16_32766, fnname: "mod_int16_32766", in: 0, want: 0},
+ test_int16{fn: mod_32766_int16, fnname: "mod_32766_int16", in: 1, want: 0},
+ test_int16{fn: mod_int16_32766, fnname: "mod_int16_32766", in: 1, want: 1},
+ test_int16{fn: mod_32766_int16, fnname: "mod_32766_int16", in: 32766, want: 0},
+ test_int16{fn: mod_int16_32766, fnname: "mod_int16_32766", in: 32766, want: 0},
+ test_int16{fn: mod_32766_int16, fnname: "mod_32766_int16", in: 32767, want: 32766},
+ test_int16{fn: mod_int16_32766, fnname: "mod_int16_32766", in: 32767, want: 1},
+ test_int16{fn: mod_32767_int16, fnname: "mod_32767_int16", in: -32768, want: 32767},
+ test_int16{fn: mod_int16_32767, fnname: "mod_int16_32767", in: -32768, want: -1},
+ test_int16{fn: mod_32767_int16, fnname: "mod_32767_int16", in: -32767, want: 0},
+ test_int16{fn: mod_int16_32767, fnname: "mod_int16_32767", in: -32767, want: 0},
+ test_int16{fn: mod_32767_int16, fnname: "mod_32767_int16", in: -1, want: 0},
+ test_int16{fn: mod_int16_32767, fnname: "mod_int16_32767", in: -1, want: -1},
+ test_int16{fn: mod_int16_32767, fnname: "mod_int16_32767", in: 0, want: 0},
+ test_int16{fn: mod_32767_int16, fnname: "mod_32767_int16", in: 1, want: 0},
+ test_int16{fn: mod_int16_32767, fnname: "mod_int16_32767", in: 1, want: 1},
+ test_int16{fn: mod_32767_int16, fnname: "mod_32767_int16", in: 32766, want: 1},
+ test_int16{fn: mod_int16_32767, fnname: "mod_int16_32767", in: 32766, want: 32766},
+ test_int16{fn: mod_32767_int16, fnname: "mod_32767_int16", in: 32767, want: 0},
+ test_int16{fn: mod_int16_32767, fnname: "mod_int16_32767", in: 32767, want: 0},
+ test_int16{fn: and_Neg32768_int16, fnname: "and_Neg32768_int16", in: -32768, want: -32768},
+ test_int16{fn: and_int16_Neg32768, fnname: "and_int16_Neg32768", in: -32768, want: -32768},
+ test_int16{fn: and_Neg32768_int16, fnname: "and_Neg32768_int16", in: -32767, want: -32768},
+ test_int16{fn: and_int16_Neg32768, fnname: "and_int16_Neg32768", in: -32767, want: -32768},
+ test_int16{fn: and_Neg32768_int16, fnname: "and_Neg32768_int16", in: -1, want: -32768},
+ test_int16{fn: and_int16_Neg32768, fnname: "and_int16_Neg32768", in: -1, want: -32768},
+ test_int16{fn: and_Neg32768_int16, fnname: "and_Neg32768_int16", in: 0, want: 0},
+ test_int16{fn: and_int16_Neg32768, fnname: "and_int16_Neg32768", in: 0, want: 0},
+ test_int16{fn: and_Neg32768_int16, fnname: "and_Neg32768_int16", in: 1, want: 0},
+ test_int16{fn: and_int16_Neg32768, fnname: "and_int16_Neg32768", in: 1, want: 0},
+ test_int16{fn: and_Neg32768_int16, fnname: "and_Neg32768_int16", in: 32766, want: 0},
+ test_int16{fn: and_int16_Neg32768, fnname: "and_int16_Neg32768", in: 32766, want: 0},
+ test_int16{fn: and_Neg32768_int16, fnname: "and_Neg32768_int16", in: 32767, want: 0},
+ test_int16{fn: and_int16_Neg32768, fnname: "and_int16_Neg32768", in: 32767, want: 0},
+ test_int16{fn: and_Neg32767_int16, fnname: "and_Neg32767_int16", in: -32768, want: -32768},
+ test_int16{fn: and_int16_Neg32767, fnname: "and_int16_Neg32767", in: -32768, want: -32768},
+ test_int16{fn: and_Neg32767_int16, fnname: "and_Neg32767_int16", in: -32767, want: -32767},
+ test_int16{fn: and_int16_Neg32767, fnname: "and_int16_Neg32767", in: -32767, want: -32767},
+ test_int16{fn: and_Neg32767_int16, fnname: "and_Neg32767_int16", in: -1, want: -32767},
+ test_int16{fn: and_int16_Neg32767, fnname: "and_int16_Neg32767", in: -1, want: -32767},
+ test_int16{fn: and_Neg32767_int16, fnname: "and_Neg32767_int16", in: 0, want: 0},
+ test_int16{fn: and_int16_Neg32767, fnname: "and_int16_Neg32767", in: 0, want: 0},
+ test_int16{fn: and_Neg32767_int16, fnname: "and_Neg32767_int16", in: 1, want: 1},
+ test_int16{fn: and_int16_Neg32767, fnname: "and_int16_Neg32767", in: 1, want: 1},
+ test_int16{fn: and_Neg32767_int16, fnname: "and_Neg32767_int16", in: 32766, want: 0},
+ test_int16{fn: and_int16_Neg32767, fnname: "and_int16_Neg32767", in: 32766, want: 0},
+ test_int16{fn: and_Neg32767_int16, fnname: "and_Neg32767_int16", in: 32767, want: 1},
+ test_int16{fn: and_int16_Neg32767, fnname: "and_int16_Neg32767", in: 32767, want: 1},
+ test_int16{fn: and_Neg1_int16, fnname: "and_Neg1_int16", in: -32768, want: -32768},
+ test_int16{fn: and_int16_Neg1, fnname: "and_int16_Neg1", in: -32768, want: -32768},
+ test_int16{fn: and_Neg1_int16, fnname: "and_Neg1_int16", in: -32767, want: -32767},
+ test_int16{fn: and_int16_Neg1, fnname: "and_int16_Neg1", in: -32767, want: -32767},
+ test_int16{fn: and_Neg1_int16, fnname: "and_Neg1_int16", in: -1, want: -1},
+ test_int16{fn: and_int16_Neg1, fnname: "and_int16_Neg1", in: -1, want: -1},
+ test_int16{fn: and_Neg1_int16, fnname: "and_Neg1_int16", in: 0, want: 0},
+ test_int16{fn: and_int16_Neg1, fnname: "and_int16_Neg1", in: 0, want: 0},
+ test_int16{fn: and_Neg1_int16, fnname: "and_Neg1_int16", in: 1, want: 1},
+ test_int16{fn: and_int16_Neg1, fnname: "and_int16_Neg1", in: 1, want: 1},
+ test_int16{fn: and_Neg1_int16, fnname: "and_Neg1_int16", in: 32766, want: 32766},
+ test_int16{fn: and_int16_Neg1, fnname: "and_int16_Neg1", in: 32766, want: 32766},
+ test_int16{fn: and_Neg1_int16, fnname: "and_Neg1_int16", in: 32767, want: 32767},
+ test_int16{fn: and_int16_Neg1, fnname: "and_int16_Neg1", in: 32767, want: 32767},
+ test_int16{fn: and_0_int16, fnname: "and_0_int16", in: -32768, want: 0},
+ test_int16{fn: and_int16_0, fnname: "and_int16_0", in: -32768, want: 0},
+ test_int16{fn: and_0_int16, fnname: "and_0_int16", in: -32767, want: 0},
+ test_int16{fn: and_int16_0, fnname: "and_int16_0", in: -32767, want: 0},
+ test_int16{fn: and_0_int16, fnname: "and_0_int16", in: -1, want: 0},
+ test_int16{fn: and_int16_0, fnname: "and_int16_0", in: -1, want: 0},
+ test_int16{fn: and_0_int16, fnname: "and_0_int16", in: 0, want: 0},
+ test_int16{fn: and_int16_0, fnname: "and_int16_0", in: 0, want: 0},
+ test_int16{fn: and_0_int16, fnname: "and_0_int16", in: 1, want: 0},
+ test_int16{fn: and_int16_0, fnname: "and_int16_0", in: 1, want: 0},
+ test_int16{fn: and_0_int16, fnname: "and_0_int16", in: 32766, want: 0},
+ test_int16{fn: and_int16_0, fnname: "and_int16_0", in: 32766, want: 0},
+ test_int16{fn: and_0_int16, fnname: "and_0_int16", in: 32767, want: 0},
+ test_int16{fn: and_int16_0, fnname: "and_int16_0", in: 32767, want: 0},
+ test_int16{fn: and_1_int16, fnname: "and_1_int16", in: -32768, want: 0},
+ test_int16{fn: and_int16_1, fnname: "and_int16_1", in: -32768, want: 0},
+ test_int16{fn: and_1_int16, fnname: "and_1_int16", in: -32767, want: 1},
+ test_int16{fn: and_int16_1, fnname: "and_int16_1", in: -32767, want: 1},
+ test_int16{fn: and_1_int16, fnname: "and_1_int16", in: -1, want: 1},
+ test_int16{fn: and_int16_1, fnname: "and_int16_1", in: -1, want: 1},
+ test_int16{fn: and_1_int16, fnname: "and_1_int16", in: 0, want: 0},
+ test_int16{fn: and_int16_1, fnname: "and_int16_1", in: 0, want: 0},
+ test_int16{fn: and_1_int16, fnname: "and_1_int16", in: 1, want: 1},
+ test_int16{fn: and_int16_1, fnname: "and_int16_1", in: 1, want: 1},
+ test_int16{fn: and_1_int16, fnname: "and_1_int16", in: 32766, want: 0},
+ test_int16{fn: and_int16_1, fnname: "and_int16_1", in: 32766, want: 0},
+ test_int16{fn: and_1_int16, fnname: "and_1_int16", in: 32767, want: 1},
+ test_int16{fn: and_int16_1, fnname: "and_int16_1", in: 32767, want: 1},
+ test_int16{fn: and_32766_int16, fnname: "and_32766_int16", in: -32768, want: 0},
+ test_int16{fn: and_int16_32766, fnname: "and_int16_32766", in: -32768, want: 0},
+ test_int16{fn: and_32766_int16, fnname: "and_32766_int16", in: -32767, want: 0},
+ test_int16{fn: and_int16_32766, fnname: "and_int16_32766", in: -32767, want: 0},
+ test_int16{fn: and_32766_int16, fnname: "and_32766_int16", in: -1, want: 32766},
+ test_int16{fn: and_int16_32766, fnname: "and_int16_32766", in: -1, want: 32766},
+ test_int16{fn: and_32766_int16, fnname: "and_32766_int16", in: 0, want: 0},
+ test_int16{fn: and_int16_32766, fnname: "and_int16_32766", in: 0, want: 0},
+ test_int16{fn: and_32766_int16, fnname: "and_32766_int16", in: 1, want: 0},
+ test_int16{fn: and_int16_32766, fnname: "and_int16_32766", in: 1, want: 0},
+ test_int16{fn: and_32766_int16, fnname: "and_32766_int16", in: 32766, want: 32766},
+ test_int16{fn: and_int16_32766, fnname: "and_int16_32766", in: 32766, want: 32766},
+ test_int16{fn: and_32766_int16, fnname: "and_32766_int16", in: 32767, want: 32766},
+ test_int16{fn: and_int16_32766, fnname: "and_int16_32766", in: 32767, want: 32766},
+ test_int16{fn: and_32767_int16, fnname: "and_32767_int16", in: -32768, want: 0},
+ test_int16{fn: and_int16_32767, fnname: "and_int16_32767", in: -32768, want: 0},
+ test_int16{fn: and_32767_int16, fnname: "and_32767_int16", in: -32767, want: 1},
+ test_int16{fn: and_int16_32767, fnname: "and_int16_32767", in: -32767, want: 1},
+ test_int16{fn: and_32767_int16, fnname: "and_32767_int16", in: -1, want: 32767},
+ test_int16{fn: and_int16_32767, fnname: "and_int16_32767", in: -1, want: 32767},
+ test_int16{fn: and_32767_int16, fnname: "and_32767_int16", in: 0, want: 0},
+ test_int16{fn: and_int16_32767, fnname: "and_int16_32767", in: 0, want: 0},
+ test_int16{fn: and_32767_int16, fnname: "and_32767_int16", in: 1, want: 1},
+ test_int16{fn: and_int16_32767, fnname: "and_int16_32767", in: 1, want: 1},
+ test_int16{fn: and_32767_int16, fnname: "and_32767_int16", in: 32766, want: 32766},
+ test_int16{fn: and_int16_32767, fnname: "and_int16_32767", in: 32766, want: 32766},
+ test_int16{fn: and_32767_int16, fnname: "and_32767_int16", in: 32767, want: 32767},
+ test_int16{fn: and_int16_32767, fnname: "and_int16_32767", in: 32767, want: 32767},
+ test_int16{fn: or_Neg32768_int16, fnname: "or_Neg32768_int16", in: -32768, want: -32768},
+ test_int16{fn: or_int16_Neg32768, fnname: "or_int16_Neg32768", in: -32768, want: -32768},
+ test_int16{fn: or_Neg32768_int16, fnname: "or_Neg32768_int16", in: -32767, want: -32767},
+ test_int16{fn: or_int16_Neg32768, fnname: "or_int16_Neg32768", in: -32767, want: -32767},
+ test_int16{fn: or_Neg32768_int16, fnname: "or_Neg32768_int16", in: -1, want: -1},
+ test_int16{fn: or_int16_Neg32768, fnname: "or_int16_Neg32768", in: -1, want: -1},
+ test_int16{fn: or_Neg32768_int16, fnname: "or_Neg32768_int16", in: 0, want: -32768},
+ test_int16{fn: or_int16_Neg32768, fnname: "or_int16_Neg32768", in: 0, want: -32768},
+ test_int16{fn: or_Neg32768_int16, fnname: "or_Neg32768_int16", in: 1, want: -32767},
+ test_int16{fn: or_int16_Neg32768, fnname: "or_int16_Neg32768", in: 1, want: -32767},
+ test_int16{fn: or_Neg32768_int16, fnname: "or_Neg32768_int16", in: 32766, want: -2},
+ test_int16{fn: or_int16_Neg32768, fnname: "or_int16_Neg32768", in: 32766, want: -2},
+ test_int16{fn: or_Neg32768_int16, fnname: "or_Neg32768_int16", in: 32767, want: -1},
+ test_int16{fn: or_int16_Neg32768, fnname: "or_int16_Neg32768", in: 32767, want: -1},
+ test_int16{fn: or_Neg32767_int16, fnname: "or_Neg32767_int16", in: -32768, want: -32767},
+ test_int16{fn: or_int16_Neg32767, fnname: "or_int16_Neg32767", in: -32768, want: -32767},
+ test_int16{fn: or_Neg32767_int16, fnname: "or_Neg32767_int16", in: -32767, want: -32767},
+ test_int16{fn: or_int16_Neg32767, fnname: "or_int16_Neg32767", in: -32767, want: -32767},
+ test_int16{fn: or_Neg32767_int16, fnname: "or_Neg32767_int16", in: -1, want: -1},
+ test_int16{fn: or_int16_Neg32767, fnname: "or_int16_Neg32767", in: -1, want: -1},
+ test_int16{fn: or_Neg32767_int16, fnname: "or_Neg32767_int16", in: 0, want: -32767},
+ test_int16{fn: or_int16_Neg32767, fnname: "or_int16_Neg32767", in: 0, want: -32767},
+ test_int16{fn: or_Neg32767_int16, fnname: "or_Neg32767_int16", in: 1, want: -32767},
+ test_int16{fn: or_int16_Neg32767, fnname: "or_int16_Neg32767", in: 1, want: -32767},
+ test_int16{fn: or_Neg32767_int16, fnname: "or_Neg32767_int16", in: 32766, want: -1},
+ test_int16{fn: or_int16_Neg32767, fnname: "or_int16_Neg32767", in: 32766, want: -1},
+ test_int16{fn: or_Neg32767_int16, fnname: "or_Neg32767_int16", in: 32767, want: -1},
+ test_int16{fn: or_int16_Neg32767, fnname: "or_int16_Neg32767", in: 32767, want: -1},
+ test_int16{fn: or_Neg1_int16, fnname: "or_Neg1_int16", in: -32768, want: -1},
+ test_int16{fn: or_int16_Neg1, fnname: "or_int16_Neg1", in: -32768, want: -1},
+ test_int16{fn: or_Neg1_int16, fnname: "or_Neg1_int16", in: -32767, want: -1},
+ test_int16{fn: or_int16_Neg1, fnname: "or_int16_Neg1", in: -32767, want: -1},
+ test_int16{fn: or_Neg1_int16, fnname: "or_Neg1_int16", in: -1, want: -1},
+ test_int16{fn: or_int16_Neg1, fnname: "or_int16_Neg1", in: -1, want: -1},
+ test_int16{fn: or_Neg1_int16, fnname: "or_Neg1_int16", in: 0, want: -1},
+ test_int16{fn: or_int16_Neg1, fnname: "or_int16_Neg1", in: 0, want: -1},
+ test_int16{fn: or_Neg1_int16, fnname: "or_Neg1_int16", in: 1, want: -1},
+ test_int16{fn: or_int16_Neg1, fnname: "or_int16_Neg1", in: 1, want: -1},
+ test_int16{fn: or_Neg1_int16, fnname: "or_Neg1_int16", in: 32766, want: -1},
+ test_int16{fn: or_int16_Neg1, fnname: "or_int16_Neg1", in: 32766, want: -1},
+ test_int16{fn: or_Neg1_int16, fnname: "or_Neg1_int16", in: 32767, want: -1},
+ test_int16{fn: or_int16_Neg1, fnname: "or_int16_Neg1", in: 32767, want: -1},
+ test_int16{fn: or_0_int16, fnname: "or_0_int16", in: -32768, want: -32768},
+ test_int16{fn: or_int16_0, fnname: "or_int16_0", in: -32768, want: -32768},
+ test_int16{fn: or_0_int16, fnname: "or_0_int16", in: -32767, want: -32767},
+ test_int16{fn: or_int16_0, fnname: "or_int16_0", in: -32767, want: -32767},
+ test_int16{fn: or_0_int16, fnname: "or_0_int16", in: -1, want: -1},
+ test_int16{fn: or_int16_0, fnname: "or_int16_0", in: -1, want: -1},
+ test_int16{fn: or_0_int16, fnname: "or_0_int16", in: 0, want: 0},
+ test_int16{fn: or_int16_0, fnname: "or_int16_0", in: 0, want: 0},
+ test_int16{fn: or_0_int16, fnname: "or_0_int16", in: 1, want: 1},
+ test_int16{fn: or_int16_0, fnname: "or_int16_0", in: 1, want: 1},
+ test_int16{fn: or_0_int16, fnname: "or_0_int16", in: 32766, want: 32766},
+ test_int16{fn: or_int16_0, fnname: "or_int16_0", in: 32766, want: 32766},
+ test_int16{fn: or_0_int16, fnname: "or_0_int16", in: 32767, want: 32767},
+ test_int16{fn: or_int16_0, fnname: "or_int16_0", in: 32767, want: 32767},
+ test_int16{fn: or_1_int16, fnname: "or_1_int16", in: -32768, want: -32767},
+ test_int16{fn: or_int16_1, fnname: "or_int16_1", in: -32768, want: -32767},
+ test_int16{fn: or_1_int16, fnname: "or_1_int16", in: -32767, want: -32767},
+ test_int16{fn: or_int16_1, fnname: "or_int16_1", in: -32767, want: -32767},
+ test_int16{fn: or_1_int16, fnname: "or_1_int16", in: -1, want: -1},
+ test_int16{fn: or_int16_1, fnname: "or_int16_1", in: -1, want: -1},
+ test_int16{fn: or_1_int16, fnname: "or_1_int16", in: 0, want: 1},
+ test_int16{fn: or_int16_1, fnname: "or_int16_1", in: 0, want: 1},
+ test_int16{fn: or_1_int16, fnname: "or_1_int16", in: 1, want: 1},
+ test_int16{fn: or_int16_1, fnname: "or_int16_1", in: 1, want: 1},
+ test_int16{fn: or_1_int16, fnname: "or_1_int16", in: 32766, want: 32767},
+ test_int16{fn: or_int16_1, fnname: "or_int16_1", in: 32766, want: 32767},
+ test_int16{fn: or_1_int16, fnname: "or_1_int16", in: 32767, want: 32767},
+ test_int16{fn: or_int16_1, fnname: "or_int16_1", in: 32767, want: 32767},
+ test_int16{fn: or_32766_int16, fnname: "or_32766_int16", in: -32768, want: -2},
+ test_int16{fn: or_int16_32766, fnname: "or_int16_32766", in: -32768, want: -2},
+ test_int16{fn: or_32766_int16, fnname: "or_32766_int16", in: -32767, want: -1},
+ test_int16{fn: or_int16_32766, fnname: "or_int16_32766", in: -32767, want: -1},
+ test_int16{fn: or_32766_int16, fnname: "or_32766_int16", in: -1, want: -1},
+ test_int16{fn: or_int16_32766, fnname: "or_int16_32766", in: -1, want: -1},
+ test_int16{fn: or_32766_int16, fnname: "or_32766_int16", in: 0, want: 32766},
+ test_int16{fn: or_int16_32766, fnname: "or_int16_32766", in: 0, want: 32766},
+ test_int16{fn: or_32766_int16, fnname: "or_32766_int16", in: 1, want: 32767},
+ test_int16{fn: or_int16_32766, fnname: "or_int16_32766", in: 1, want: 32767},
+ test_int16{fn: or_32766_int16, fnname: "or_32766_int16", in: 32766, want: 32766},
+ test_int16{fn: or_int16_32766, fnname: "or_int16_32766", in: 32766, want: 32766},
+ test_int16{fn: or_32766_int16, fnname: "or_32766_int16", in: 32767, want: 32767},
+ test_int16{fn: or_int16_32766, fnname: "or_int16_32766", in: 32767, want: 32767},
+ test_int16{fn: or_32767_int16, fnname: "or_32767_int16", in: -32768, want: -1},
+ test_int16{fn: or_int16_32767, fnname: "or_int16_32767", in: -32768, want: -1},
+ test_int16{fn: or_32767_int16, fnname: "or_32767_int16", in: -32767, want: -1},
+ test_int16{fn: or_int16_32767, fnname: "or_int16_32767", in: -32767, want: -1},
+ test_int16{fn: or_32767_int16, fnname: "or_32767_int16", in: -1, want: -1},
+ test_int16{fn: or_int16_32767, fnname: "or_int16_32767", in: -1, want: -1},
+ test_int16{fn: or_32767_int16, fnname: "or_32767_int16", in: 0, want: 32767},
+ test_int16{fn: or_int16_32767, fnname: "or_int16_32767", in: 0, want: 32767},
+ test_int16{fn: or_32767_int16, fnname: "or_32767_int16", in: 1, want: 32767},
+ test_int16{fn: or_int16_32767, fnname: "or_int16_32767", in: 1, want: 32767},
+ test_int16{fn: or_32767_int16, fnname: "or_32767_int16", in: 32766, want: 32767},
+ test_int16{fn: or_int16_32767, fnname: "or_int16_32767", in: 32766, want: 32767},
+ test_int16{fn: or_32767_int16, fnname: "or_32767_int16", in: 32767, want: 32767},
+ test_int16{fn: or_int16_32767, fnname: "or_int16_32767", in: 32767, want: 32767},
+ test_int16{fn: xor_Neg32768_int16, fnname: "xor_Neg32768_int16", in: -32768, want: 0},
+ test_int16{fn: xor_int16_Neg32768, fnname: "xor_int16_Neg32768", in: -32768, want: 0},
+ test_int16{fn: xor_Neg32768_int16, fnname: "xor_Neg32768_int16", in: -32767, want: 1},
+ test_int16{fn: xor_int16_Neg32768, fnname: "xor_int16_Neg32768", in: -32767, want: 1},
+ test_int16{fn: xor_Neg32768_int16, fnname: "xor_Neg32768_int16", in: -1, want: 32767},
+ test_int16{fn: xor_int16_Neg32768, fnname: "xor_int16_Neg32768", in: -1, want: 32767},
+ test_int16{fn: xor_Neg32768_int16, fnname: "xor_Neg32768_int16", in: 0, want: -32768},
+ test_int16{fn: xor_int16_Neg32768, fnname: "xor_int16_Neg32768", in: 0, want: -32768},
+ test_int16{fn: xor_Neg32768_int16, fnname: "xor_Neg32768_int16", in: 1, want: -32767},
+ test_int16{fn: xor_int16_Neg32768, fnname: "xor_int16_Neg32768", in: 1, want: -32767},
+ test_int16{fn: xor_Neg32768_int16, fnname: "xor_Neg32768_int16", in: 32766, want: -2},
+ test_int16{fn: xor_int16_Neg32768, fnname: "xor_int16_Neg32768", in: 32766, want: -2},
+ test_int16{fn: xor_Neg32768_int16, fnname: "xor_Neg32768_int16", in: 32767, want: -1},
+ test_int16{fn: xor_int16_Neg32768, fnname: "xor_int16_Neg32768", in: 32767, want: -1},
+ test_int16{fn: xor_Neg32767_int16, fnname: "xor_Neg32767_int16", in: -32768, want: 1},
+ test_int16{fn: xor_int16_Neg32767, fnname: "xor_int16_Neg32767", in: -32768, want: 1},
+ test_int16{fn: xor_Neg32767_int16, fnname: "xor_Neg32767_int16", in: -32767, want: 0},
+ test_int16{fn: xor_int16_Neg32767, fnname: "xor_int16_Neg32767", in: -32767, want: 0},
+ test_int16{fn: xor_Neg32767_int16, fnname: "xor_Neg32767_int16", in: -1, want: 32766},
+ test_int16{fn: xor_int16_Neg32767, fnname: "xor_int16_Neg32767", in: -1, want: 32766},
+ test_int16{fn: xor_Neg32767_int16, fnname: "xor_Neg32767_int16", in: 0, want: -32767},
+ test_int16{fn: xor_int16_Neg32767, fnname: "xor_int16_Neg32767", in: 0, want: -32767},
+ test_int16{fn: xor_Neg32767_int16, fnname: "xor_Neg32767_int16", in: 1, want: -32768},
+ test_int16{fn: xor_int16_Neg32767, fnname: "xor_int16_Neg32767", in: 1, want: -32768},
+ test_int16{fn: xor_Neg32767_int16, fnname: "xor_Neg32767_int16", in: 32766, want: -1},
+ test_int16{fn: xor_int16_Neg32767, fnname: "xor_int16_Neg32767", in: 32766, want: -1},
+ test_int16{fn: xor_Neg32767_int16, fnname: "xor_Neg32767_int16", in: 32767, want: -2},
+ test_int16{fn: xor_int16_Neg32767, fnname: "xor_int16_Neg32767", in: 32767, want: -2},
+ test_int16{fn: xor_Neg1_int16, fnname: "xor_Neg1_int16", in: -32768, want: 32767},
+ test_int16{fn: xor_int16_Neg1, fnname: "xor_int16_Neg1", in: -32768, want: 32767},
+ test_int16{fn: xor_Neg1_int16, fnname: "xor_Neg1_int16", in: -32767, want: 32766},
+ test_int16{fn: xor_int16_Neg1, fnname: "xor_int16_Neg1", in: -32767, want: 32766},
+ test_int16{fn: xor_Neg1_int16, fnname: "xor_Neg1_int16", in: -1, want: 0},
+ test_int16{fn: xor_int16_Neg1, fnname: "xor_int16_Neg1", in: -1, want: 0},
+ test_int16{fn: xor_Neg1_int16, fnname: "xor_Neg1_int16", in: 0, want: -1},
+ test_int16{fn: xor_int16_Neg1, fnname: "xor_int16_Neg1", in: 0, want: -1},
+ test_int16{fn: xor_Neg1_int16, fnname: "xor_Neg1_int16", in: 1, want: -2},
+ test_int16{fn: xor_int16_Neg1, fnname: "xor_int16_Neg1", in: 1, want: -2},
+ test_int16{fn: xor_Neg1_int16, fnname: "xor_Neg1_int16", in: 32766, want: -32767},
+ test_int16{fn: xor_int16_Neg1, fnname: "xor_int16_Neg1", in: 32766, want: -32767},
+ test_int16{fn: xor_Neg1_int16, fnname: "xor_Neg1_int16", in: 32767, want: -32768},
+ test_int16{fn: xor_int16_Neg1, fnname: "xor_int16_Neg1", in: 32767, want: -32768},
+ test_int16{fn: xor_0_int16, fnname: "xor_0_int16", in: -32768, want: -32768},
+ test_int16{fn: xor_int16_0, fnname: "xor_int16_0", in: -32768, want: -32768},
+ test_int16{fn: xor_0_int16, fnname: "xor_0_int16", in: -32767, want: -32767},
+ test_int16{fn: xor_int16_0, fnname: "xor_int16_0", in: -32767, want: -32767},
+ test_int16{fn: xor_0_int16, fnname: "xor_0_int16", in: -1, want: -1},
+ test_int16{fn: xor_int16_0, fnname: "xor_int16_0", in: -1, want: -1},
+ test_int16{fn: xor_0_int16, fnname: "xor_0_int16", in: 0, want: 0},
+ test_int16{fn: xor_int16_0, fnname: "xor_int16_0", in: 0, want: 0},
+ test_int16{fn: xor_0_int16, fnname: "xor_0_int16", in: 1, want: 1},
+ test_int16{fn: xor_int16_0, fnname: "xor_int16_0", in: 1, want: 1},
+ test_int16{fn: xor_0_int16, fnname: "xor_0_int16", in: 32766, want: 32766},
+ test_int16{fn: xor_int16_0, fnname: "xor_int16_0", in: 32766, want: 32766},
+ test_int16{fn: xor_0_int16, fnname: "xor_0_int16", in: 32767, want: 32767},
+ test_int16{fn: xor_int16_0, fnname: "xor_int16_0", in: 32767, want: 32767},
+ test_int16{fn: xor_1_int16, fnname: "xor_1_int16", in: -32768, want: -32767},
+ test_int16{fn: xor_int16_1, fnname: "xor_int16_1", in: -32768, want: -32767},
+ test_int16{fn: xor_1_int16, fnname: "xor_1_int16", in: -32767, want: -32768},
+ test_int16{fn: xor_int16_1, fnname: "xor_int16_1", in: -32767, want: -32768},
+ test_int16{fn: xor_1_int16, fnname: "xor_1_int16", in: -1, want: -2},
+ test_int16{fn: xor_int16_1, fnname: "xor_int16_1", in: -1, want: -2},
+ test_int16{fn: xor_1_int16, fnname: "xor_1_int16", in: 0, want: 1},
+ test_int16{fn: xor_int16_1, fnname: "xor_int16_1", in: 0, want: 1},
+ test_int16{fn: xor_1_int16, fnname: "xor_1_int16", in: 1, want: 0},
+ test_int16{fn: xor_int16_1, fnname: "xor_int16_1", in: 1, want: 0},
+ test_int16{fn: xor_1_int16, fnname: "xor_1_int16", in: 32766, want: 32767},
+ test_int16{fn: xor_int16_1, fnname: "xor_int16_1", in: 32766, want: 32767},
+ test_int16{fn: xor_1_int16, fnname: "xor_1_int16", in: 32767, want: 32766},
+ test_int16{fn: xor_int16_1, fnname: "xor_int16_1", in: 32767, want: 32766},
+ test_int16{fn: xor_32766_int16, fnname: "xor_32766_int16", in: -32768, want: -2},
+ test_int16{fn: xor_int16_32766, fnname: "xor_int16_32766", in: -32768, want: -2},
+ test_int16{fn: xor_32766_int16, fnname: "xor_32766_int16", in: -32767, want: -1},
+ test_int16{fn: xor_int16_32766, fnname: "xor_int16_32766", in: -32767, want: -1},
+ test_int16{fn: xor_32766_int16, fnname: "xor_32766_int16", in: -1, want: -32767},
+ test_int16{fn: xor_int16_32766, fnname: "xor_int16_32766", in: -1, want: -32767},
+ test_int16{fn: xor_32766_int16, fnname: "xor_32766_int16", in: 0, want: 32766},
+ test_int16{fn: xor_int16_32766, fnname: "xor_int16_32766", in: 0, want: 32766},
+ test_int16{fn: xor_32766_int16, fnname: "xor_32766_int16", in: 1, want: 32767},
+ test_int16{fn: xor_int16_32766, fnname: "xor_int16_32766", in: 1, want: 32767},
+ test_int16{fn: xor_32766_int16, fnname: "xor_32766_int16", in: 32766, want: 0},
+ test_int16{fn: xor_int16_32766, fnname: "xor_int16_32766", in: 32766, want: 0},
+ test_int16{fn: xor_32766_int16, fnname: "xor_32766_int16", in: 32767, want: 1},
+ test_int16{fn: xor_int16_32766, fnname: "xor_int16_32766", in: 32767, want: 1},
+ test_int16{fn: xor_32767_int16, fnname: "xor_32767_int16", in: -32768, want: -1},
+ test_int16{fn: xor_int16_32767, fnname: "xor_int16_32767", in: -32768, want: -1},
+ test_int16{fn: xor_32767_int16, fnname: "xor_32767_int16", in: -32767, want: -2},
+ test_int16{fn: xor_int16_32767, fnname: "xor_int16_32767", in: -32767, want: -2},
+ test_int16{fn: xor_32767_int16, fnname: "xor_32767_int16", in: -1, want: -32768},
+ test_int16{fn: xor_int16_32767, fnname: "xor_int16_32767", in: -1, want: -32768},
+ test_int16{fn: xor_32767_int16, fnname: "xor_32767_int16", in: 0, want: 32767},
+ test_int16{fn: xor_int16_32767, fnname: "xor_int16_32767", in: 0, want: 32767},
+ test_int16{fn: xor_32767_int16, fnname: "xor_32767_int16", in: 1, want: 32766},
+ test_int16{fn: xor_int16_32767, fnname: "xor_int16_32767", in: 1, want: 32766},
+ test_int16{fn: xor_32767_int16, fnname: "xor_32767_int16", in: 32766, want: 1},
+ test_int16{fn: xor_int16_32767, fnname: "xor_int16_32767", in: 32766, want: 1},
+ test_int16{fn: xor_32767_int16, fnname: "xor_32767_int16", in: 32767, want: 0},
+ test_int16{fn: xor_int16_32767, fnname: "xor_int16_32767", in: 32767, want: 0}}
+
+type test_uint8 struct {
+ fn func(uint8) uint8
+ fnname string
+ in uint8
+ want uint8
+}
+
+var tests_uint8 = []test_uint8{
+
+ test_uint8{fn: add_0_uint8, fnname: "add_0_uint8", in: 0, want: 0},
+ test_uint8{fn: add_uint8_0, fnname: "add_uint8_0", in: 0, want: 0},
+ test_uint8{fn: add_0_uint8, fnname: "add_0_uint8", in: 1, want: 1},
+ test_uint8{fn: add_uint8_0, fnname: "add_uint8_0", in: 1, want: 1},
+ test_uint8{fn: add_0_uint8, fnname: "add_0_uint8", in: 255, want: 255},
+ test_uint8{fn: add_uint8_0, fnname: "add_uint8_0", in: 255, want: 255},
+ test_uint8{fn: add_1_uint8, fnname: "add_1_uint8", in: 0, want: 1},
+ test_uint8{fn: add_uint8_1, fnname: "add_uint8_1", in: 0, want: 1},
+ test_uint8{fn: add_1_uint8, fnname: "add_1_uint8", in: 1, want: 2},
+ test_uint8{fn: add_uint8_1, fnname: "add_uint8_1", in: 1, want: 2},
+ test_uint8{fn: add_1_uint8, fnname: "add_1_uint8", in: 255, want: 0},
+ test_uint8{fn: add_uint8_1, fnname: "add_uint8_1", in: 255, want: 0},
+ test_uint8{fn: add_255_uint8, fnname: "add_255_uint8", in: 0, want: 255},
+ test_uint8{fn: add_uint8_255, fnname: "add_uint8_255", in: 0, want: 255},
+ test_uint8{fn: add_255_uint8, fnname: "add_255_uint8", in: 1, want: 0},
+ test_uint8{fn: add_uint8_255, fnname: "add_uint8_255", in: 1, want: 0},
+ test_uint8{fn: add_255_uint8, fnname: "add_255_uint8", in: 255, want: 254},
+ test_uint8{fn: add_uint8_255, fnname: "add_uint8_255", in: 255, want: 254},
+ test_uint8{fn: sub_0_uint8, fnname: "sub_0_uint8", in: 0, want: 0},
+ test_uint8{fn: sub_uint8_0, fnname: "sub_uint8_0", in: 0, want: 0},
+ test_uint8{fn: sub_0_uint8, fnname: "sub_0_uint8", in: 1, want: 255},
+ test_uint8{fn: sub_uint8_0, fnname: "sub_uint8_0", in: 1, want: 1},
+ test_uint8{fn: sub_0_uint8, fnname: "sub_0_uint8", in: 255, want: 1},
+ test_uint8{fn: sub_uint8_0, fnname: "sub_uint8_0", in: 255, want: 255},
+ test_uint8{fn: sub_1_uint8, fnname: "sub_1_uint8", in: 0, want: 1},
+ test_uint8{fn: sub_uint8_1, fnname: "sub_uint8_1", in: 0, want: 255},
+ test_uint8{fn: sub_1_uint8, fnname: "sub_1_uint8", in: 1, want: 0},
+ test_uint8{fn: sub_uint8_1, fnname: "sub_uint8_1", in: 1, want: 0},
+ test_uint8{fn: sub_1_uint8, fnname: "sub_1_uint8", in: 255, want: 2},
+ test_uint8{fn: sub_uint8_1, fnname: "sub_uint8_1", in: 255, want: 254},
+ test_uint8{fn: sub_255_uint8, fnname: "sub_255_uint8", in: 0, want: 255},
+ test_uint8{fn: sub_uint8_255, fnname: "sub_uint8_255", in: 0, want: 1},
+ test_uint8{fn: sub_255_uint8, fnname: "sub_255_uint8", in: 1, want: 254},
+ test_uint8{fn: sub_uint8_255, fnname: "sub_uint8_255", in: 1, want: 2},
+ test_uint8{fn: sub_255_uint8, fnname: "sub_255_uint8", in: 255, want: 0},
+ test_uint8{fn: sub_uint8_255, fnname: "sub_uint8_255", in: 255, want: 0},
+ test_uint8{fn: div_0_uint8, fnname: "div_0_uint8", in: 1, want: 0},
+ test_uint8{fn: div_0_uint8, fnname: "div_0_uint8", in: 255, want: 0},
+ test_uint8{fn: div_uint8_1, fnname: "div_uint8_1", in: 0, want: 0},
+ test_uint8{fn: div_1_uint8, fnname: "div_1_uint8", in: 1, want: 1},
+ test_uint8{fn: div_uint8_1, fnname: "div_uint8_1", in: 1, want: 1},
+ test_uint8{fn: div_1_uint8, fnname: "div_1_uint8", in: 255, want: 0},
+ test_uint8{fn: div_uint8_1, fnname: "div_uint8_1", in: 255, want: 255},
+ test_uint8{fn: div_uint8_255, fnname: "div_uint8_255", in: 0, want: 0},
+ test_uint8{fn: div_255_uint8, fnname: "div_255_uint8", in: 1, want: 255},
+ test_uint8{fn: div_uint8_255, fnname: "div_uint8_255", in: 1, want: 0},
+ test_uint8{fn: div_255_uint8, fnname: "div_255_uint8", in: 255, want: 1},
+ test_uint8{fn: div_uint8_255, fnname: "div_uint8_255", in: 255, want: 1},
+ test_uint8{fn: mul_0_uint8, fnname: "mul_0_uint8", in: 0, want: 0},
+ test_uint8{fn: mul_uint8_0, fnname: "mul_uint8_0", in: 0, want: 0},
+ test_uint8{fn: mul_0_uint8, fnname: "mul_0_uint8", in: 1, want: 0},
+ test_uint8{fn: mul_uint8_0, fnname: "mul_uint8_0", in: 1, want: 0},
+ test_uint8{fn: mul_0_uint8, fnname: "mul_0_uint8", in: 255, want: 0},
+ test_uint8{fn: mul_uint8_0, fnname: "mul_uint8_0", in: 255, want: 0},
+ test_uint8{fn: mul_1_uint8, fnname: "mul_1_uint8", in: 0, want: 0},
+ test_uint8{fn: mul_uint8_1, fnname: "mul_uint8_1", in: 0, want: 0},
+ test_uint8{fn: mul_1_uint8, fnname: "mul_1_uint8", in: 1, want: 1},
+ test_uint8{fn: mul_uint8_1, fnname: "mul_uint8_1", in: 1, want: 1},
+ test_uint8{fn: mul_1_uint8, fnname: "mul_1_uint8", in: 255, want: 255},
+ test_uint8{fn: mul_uint8_1, fnname: "mul_uint8_1", in: 255, want: 255},
+ test_uint8{fn: mul_255_uint8, fnname: "mul_255_uint8", in: 0, want: 0},
+ test_uint8{fn: mul_uint8_255, fnname: "mul_uint8_255", in: 0, want: 0},
+ test_uint8{fn: mul_255_uint8, fnname: "mul_255_uint8", in: 1, want: 255},
+ test_uint8{fn: mul_uint8_255, fnname: "mul_uint8_255", in: 1, want: 255},
+ test_uint8{fn: mul_255_uint8, fnname: "mul_255_uint8", in: 255, want: 1},
+ test_uint8{fn: mul_uint8_255, fnname: "mul_uint8_255", in: 255, want: 1},
+ test_uint8{fn: lsh_0_uint8, fnname: "lsh_0_uint8", in: 0, want: 0},
+ test_uint8{fn: lsh_uint8_0, fnname: "lsh_uint8_0", in: 0, want: 0},
+ test_uint8{fn: lsh_0_uint8, fnname: "lsh_0_uint8", in: 1, want: 0},
+ test_uint8{fn: lsh_uint8_0, fnname: "lsh_uint8_0", in: 1, want: 1},
+ test_uint8{fn: lsh_0_uint8, fnname: "lsh_0_uint8", in: 255, want: 0},
+ test_uint8{fn: lsh_uint8_0, fnname: "lsh_uint8_0", in: 255, want: 255},
+ test_uint8{fn: lsh_1_uint8, fnname: "lsh_1_uint8", in: 0, want: 1},
+ test_uint8{fn: lsh_uint8_1, fnname: "lsh_uint8_1", in: 0, want: 0},
+ test_uint8{fn: lsh_1_uint8, fnname: "lsh_1_uint8", in: 1, want: 2},
+ test_uint8{fn: lsh_uint8_1, fnname: "lsh_uint8_1", in: 1, want: 2},
+ test_uint8{fn: lsh_1_uint8, fnname: "lsh_1_uint8", in: 255, want: 0},
+ test_uint8{fn: lsh_uint8_1, fnname: "lsh_uint8_1", in: 255, want: 254},
+ test_uint8{fn: lsh_255_uint8, fnname: "lsh_255_uint8", in: 0, want: 255},
+ test_uint8{fn: lsh_uint8_255, fnname: "lsh_uint8_255", in: 0, want: 0},
+ test_uint8{fn: lsh_255_uint8, fnname: "lsh_255_uint8", in: 1, want: 254},
+ test_uint8{fn: lsh_uint8_255, fnname: "lsh_uint8_255", in: 1, want: 0},
+ test_uint8{fn: lsh_255_uint8, fnname: "lsh_255_uint8", in: 255, want: 0},
+ test_uint8{fn: lsh_uint8_255, fnname: "lsh_uint8_255", in: 255, want: 0},
+ test_uint8{fn: rsh_0_uint8, fnname: "rsh_0_uint8", in: 0, want: 0},
+ test_uint8{fn: rsh_uint8_0, fnname: "rsh_uint8_0", in: 0, want: 0},
+ test_uint8{fn: rsh_0_uint8, fnname: "rsh_0_uint8", in: 1, want: 0},
+ test_uint8{fn: rsh_uint8_0, fnname: "rsh_uint8_0", in: 1, want: 1},
+ test_uint8{fn: rsh_0_uint8, fnname: "rsh_0_uint8", in: 255, want: 0},
+ test_uint8{fn: rsh_uint8_0, fnname: "rsh_uint8_0", in: 255, want: 255},
+ test_uint8{fn: rsh_1_uint8, fnname: "rsh_1_uint8", in: 0, want: 1},
+ test_uint8{fn: rsh_uint8_1, fnname: "rsh_uint8_1", in: 0, want: 0},
+ test_uint8{fn: rsh_1_uint8, fnname: "rsh_1_uint8", in: 1, want: 0},
+ test_uint8{fn: rsh_uint8_1, fnname: "rsh_uint8_1", in: 1, want: 0},
+ test_uint8{fn: rsh_1_uint8, fnname: "rsh_1_uint8", in: 255, want: 0},
+ test_uint8{fn: rsh_uint8_1, fnname: "rsh_uint8_1", in: 255, want: 127},
+ test_uint8{fn: rsh_255_uint8, fnname: "rsh_255_uint8", in: 0, want: 255},
+ test_uint8{fn: rsh_uint8_255, fnname: "rsh_uint8_255", in: 0, want: 0},
+ test_uint8{fn: rsh_255_uint8, fnname: "rsh_255_uint8", in: 1, want: 127},
+ test_uint8{fn: rsh_uint8_255, fnname: "rsh_uint8_255", in: 1, want: 0},
+ test_uint8{fn: rsh_255_uint8, fnname: "rsh_255_uint8", in: 255, want: 0},
+ test_uint8{fn: rsh_uint8_255, fnname: "rsh_uint8_255", in: 255, want: 0},
+ test_uint8{fn: mod_0_uint8, fnname: "mod_0_uint8", in: 1, want: 0},
+ test_uint8{fn: mod_0_uint8, fnname: "mod_0_uint8", in: 255, want: 0},
+ test_uint8{fn: mod_uint8_1, fnname: "mod_uint8_1", in: 0, want: 0},
+ test_uint8{fn: mod_1_uint8, fnname: "mod_1_uint8", in: 1, want: 0},
+ test_uint8{fn: mod_uint8_1, fnname: "mod_uint8_1", in: 1, want: 0},
+ test_uint8{fn: mod_1_uint8, fnname: "mod_1_uint8", in: 255, want: 1},
+ test_uint8{fn: mod_uint8_1, fnname: "mod_uint8_1", in: 255, want: 0},
+ test_uint8{fn: mod_uint8_255, fnname: "mod_uint8_255", in: 0, want: 0},
+ test_uint8{fn: mod_255_uint8, fnname: "mod_255_uint8", in: 1, want: 0},
+ test_uint8{fn: mod_uint8_255, fnname: "mod_uint8_255", in: 1, want: 1},
+ test_uint8{fn: mod_255_uint8, fnname: "mod_255_uint8", in: 255, want: 0},
+ test_uint8{fn: mod_uint8_255, fnname: "mod_uint8_255", in: 255, want: 0},
+ test_uint8{fn: and_0_uint8, fnname: "and_0_uint8", in: 0, want: 0},
+ test_uint8{fn: and_uint8_0, fnname: "and_uint8_0", in: 0, want: 0},
+ test_uint8{fn: and_0_uint8, fnname: "and_0_uint8", in: 1, want: 0},
+ test_uint8{fn: and_uint8_0, fnname: "and_uint8_0", in: 1, want: 0},
+ test_uint8{fn: and_0_uint8, fnname: "and_0_uint8", in: 255, want: 0},
+ test_uint8{fn: and_uint8_0, fnname: "and_uint8_0", in: 255, want: 0},
+ test_uint8{fn: and_1_uint8, fnname: "and_1_uint8", in: 0, want: 0},
+ test_uint8{fn: and_uint8_1, fnname: "and_uint8_1", in: 0, want: 0},
+ test_uint8{fn: and_1_uint8, fnname: "and_1_uint8", in: 1, want: 1},
+ test_uint8{fn: and_uint8_1, fnname: "and_uint8_1", in: 1, want: 1},
+ test_uint8{fn: and_1_uint8, fnname: "and_1_uint8", in: 255, want: 1},
+ test_uint8{fn: and_uint8_1, fnname: "and_uint8_1", in: 255, want: 1},
+ test_uint8{fn: and_255_uint8, fnname: "and_255_uint8", in: 0, want: 0},
+ test_uint8{fn: and_uint8_255, fnname: "and_uint8_255", in: 0, want: 0},
+ test_uint8{fn: and_255_uint8, fnname: "and_255_uint8", in: 1, want: 1},
+ test_uint8{fn: and_uint8_255, fnname: "and_uint8_255", in: 1, want: 1},
+ test_uint8{fn: and_255_uint8, fnname: "and_255_uint8", in: 255, want: 255},
+ test_uint8{fn: and_uint8_255, fnname: "and_uint8_255", in: 255, want: 255},
+ test_uint8{fn: or_0_uint8, fnname: "or_0_uint8", in: 0, want: 0},
+ test_uint8{fn: or_uint8_0, fnname: "or_uint8_0", in: 0, want: 0},
+ test_uint8{fn: or_0_uint8, fnname: "or_0_uint8", in: 1, want: 1},
+ test_uint8{fn: or_uint8_0, fnname: "or_uint8_0", in: 1, want: 1},
+ test_uint8{fn: or_0_uint8, fnname: "or_0_uint8", in: 255, want: 255},
+ test_uint8{fn: or_uint8_0, fnname: "or_uint8_0", in: 255, want: 255},
+ test_uint8{fn: or_1_uint8, fnname: "or_1_uint8", in: 0, want: 1},
+ test_uint8{fn: or_uint8_1, fnname: "or_uint8_1", in: 0, want: 1},
+ test_uint8{fn: or_1_uint8, fnname: "or_1_uint8", in: 1, want: 1},
+ test_uint8{fn: or_uint8_1, fnname: "or_uint8_1", in: 1, want: 1},
+ test_uint8{fn: or_1_uint8, fnname: "or_1_uint8", in: 255, want: 255},
+ test_uint8{fn: or_uint8_1, fnname: "or_uint8_1", in: 255, want: 255},
+ test_uint8{fn: or_255_uint8, fnname: "or_255_uint8", in: 0, want: 255},
+ test_uint8{fn: or_uint8_255, fnname: "or_uint8_255", in: 0, want: 255},
+ test_uint8{fn: or_255_uint8, fnname: "or_255_uint8", in: 1, want: 255},
+ test_uint8{fn: or_uint8_255, fnname: "or_uint8_255", in: 1, want: 255},
+ test_uint8{fn: or_255_uint8, fnname: "or_255_uint8", in: 255, want: 255},
+ test_uint8{fn: or_uint8_255, fnname: "or_uint8_255", in: 255, want: 255},
+ test_uint8{fn: xor_0_uint8, fnname: "xor_0_uint8", in: 0, want: 0},
+ test_uint8{fn: xor_uint8_0, fnname: "xor_uint8_0", in: 0, want: 0},
+ test_uint8{fn: xor_0_uint8, fnname: "xor_0_uint8", in: 1, want: 1},
+ test_uint8{fn: xor_uint8_0, fnname: "xor_uint8_0", in: 1, want: 1},
+ test_uint8{fn: xor_0_uint8, fnname: "xor_0_uint8", in: 255, want: 255},
+ test_uint8{fn: xor_uint8_0, fnname: "xor_uint8_0", in: 255, want: 255},
+ test_uint8{fn: xor_1_uint8, fnname: "xor_1_uint8", in: 0, want: 1},
+ test_uint8{fn: xor_uint8_1, fnname: "xor_uint8_1", in: 0, want: 1},
+ test_uint8{fn: xor_1_uint8, fnname: "xor_1_uint8", in: 1, want: 0},
+ test_uint8{fn: xor_uint8_1, fnname: "xor_uint8_1", in: 1, want: 0},
+ test_uint8{fn: xor_1_uint8, fnname: "xor_1_uint8", in: 255, want: 254},
+ test_uint8{fn: xor_uint8_1, fnname: "xor_uint8_1", in: 255, want: 254},
+ test_uint8{fn: xor_255_uint8, fnname: "xor_255_uint8", in: 0, want: 255},
+ test_uint8{fn: xor_uint8_255, fnname: "xor_uint8_255", in: 0, want: 255},
+ test_uint8{fn: xor_255_uint8, fnname: "xor_255_uint8", in: 1, want: 254},
+ test_uint8{fn: xor_uint8_255, fnname: "xor_uint8_255", in: 1, want: 254},
+ test_uint8{fn: xor_255_uint8, fnname: "xor_255_uint8", in: 255, want: 0},
+ test_uint8{fn: xor_uint8_255, fnname: "xor_uint8_255", in: 255, want: 0}}
+
+type test_int8 struct {
+ fn func(int8) int8
+ fnname string
+ in int8
+ want int8
+}
+
+var tests_int8 = []test_int8{
+
+ test_int8{fn: add_Neg128_int8, fnname: "add_Neg128_int8", in: -128, want: 0},
+ test_int8{fn: add_int8_Neg128, fnname: "add_int8_Neg128", in: -128, want: 0},
+ test_int8{fn: add_Neg128_int8, fnname: "add_Neg128_int8", in: -127, want: 1},
+ test_int8{fn: add_int8_Neg128, fnname: "add_int8_Neg128", in: -127, want: 1},
+ test_int8{fn: add_Neg128_int8, fnname: "add_Neg128_int8", in: -1, want: 127},
+ test_int8{fn: add_int8_Neg128, fnname: "add_int8_Neg128", in: -1, want: 127},
+ test_int8{fn: add_Neg128_int8, fnname: "add_Neg128_int8", in: 0, want: -128},
+ test_int8{fn: add_int8_Neg128, fnname: "add_int8_Neg128", in: 0, want: -128},
+ test_int8{fn: add_Neg128_int8, fnname: "add_Neg128_int8", in: 1, want: -127},
+ test_int8{fn: add_int8_Neg128, fnname: "add_int8_Neg128", in: 1, want: -127},
+ test_int8{fn: add_Neg128_int8, fnname: "add_Neg128_int8", in: 126, want: -2},
+ test_int8{fn: add_int8_Neg128, fnname: "add_int8_Neg128", in: 126, want: -2},
+ test_int8{fn: add_Neg128_int8, fnname: "add_Neg128_int8", in: 127, want: -1},
+ test_int8{fn: add_int8_Neg128, fnname: "add_int8_Neg128", in: 127, want: -1},
+ test_int8{fn: add_Neg127_int8, fnname: "add_Neg127_int8", in: -128, want: 1},
+ test_int8{fn: add_int8_Neg127, fnname: "add_int8_Neg127", in: -128, want: 1},
+ test_int8{fn: add_Neg127_int8, fnname: "add_Neg127_int8", in: -127, want: 2},
+ test_int8{fn: add_int8_Neg127, fnname: "add_int8_Neg127", in: -127, want: 2},
+ test_int8{fn: add_Neg127_int8, fnname: "add_Neg127_int8", in: -1, want: -128},
+ test_int8{fn: add_int8_Neg127, fnname: "add_int8_Neg127", in: -1, want: -128},
+ test_int8{fn: add_Neg127_int8, fnname: "add_Neg127_int8", in: 0, want: -127},
+ test_int8{fn: add_int8_Neg127, fnname: "add_int8_Neg127", in: 0, want: -127},
+ test_int8{fn: add_Neg127_int8, fnname: "add_Neg127_int8", in: 1, want: -126},
+ test_int8{fn: add_int8_Neg127, fnname: "add_int8_Neg127", in: 1, want: -126},
+ test_int8{fn: add_Neg127_int8, fnname: "add_Neg127_int8", in: 126, want: -1},
+ test_int8{fn: add_int8_Neg127, fnname: "add_int8_Neg127", in: 126, want: -1},
+ test_int8{fn: add_Neg127_int8, fnname: "add_Neg127_int8", in: 127, want: 0},
+ test_int8{fn: add_int8_Neg127, fnname: "add_int8_Neg127", in: 127, want: 0},
+ test_int8{fn: add_Neg1_int8, fnname: "add_Neg1_int8", in: -128, want: 127},
+ test_int8{fn: add_int8_Neg1, fnname: "add_int8_Neg1", in: -128, want: 127},
+ test_int8{fn: add_Neg1_int8, fnname: "add_Neg1_int8", in: -127, want: -128},
+ test_int8{fn: add_int8_Neg1, fnname: "add_int8_Neg1", in: -127, want: -128},
+ test_int8{fn: add_Neg1_int8, fnname: "add_Neg1_int8", in: -1, want: -2},
+ test_int8{fn: add_int8_Neg1, fnname: "add_int8_Neg1", in: -1, want: -2},
+ test_int8{fn: add_Neg1_int8, fnname: "add_Neg1_int8", in: 0, want: -1},
+ test_int8{fn: add_int8_Neg1, fnname: "add_int8_Neg1", in: 0, want: -1},
+ test_int8{fn: add_Neg1_int8, fnname: "add_Neg1_int8", in: 1, want: 0},
+ test_int8{fn: add_int8_Neg1, fnname: "add_int8_Neg1", in: 1, want: 0},
+ test_int8{fn: add_Neg1_int8, fnname: "add_Neg1_int8", in: 126, want: 125},
+ test_int8{fn: add_int8_Neg1, fnname: "add_int8_Neg1", in: 126, want: 125},
+ test_int8{fn: add_Neg1_int8, fnname: "add_Neg1_int8", in: 127, want: 126},
+ test_int8{fn: add_int8_Neg1, fnname: "add_int8_Neg1", in: 127, want: 126},
+ test_int8{fn: add_0_int8, fnname: "add_0_int8", in: -128, want: -128},
+ test_int8{fn: add_int8_0, fnname: "add_int8_0", in: -128, want: -128},
+ test_int8{fn: add_0_int8, fnname: "add_0_int8", in: -127, want: -127},
+ test_int8{fn: add_int8_0, fnname: "add_int8_0", in: -127, want: -127},
+ test_int8{fn: add_0_int8, fnname: "add_0_int8", in: -1, want: -1},
+ test_int8{fn: add_int8_0, fnname: "add_int8_0", in: -1, want: -1},
+ test_int8{fn: add_0_int8, fnname: "add_0_int8", in: 0, want: 0},
+ test_int8{fn: add_int8_0, fnname: "add_int8_0", in: 0, want: 0},
+ test_int8{fn: add_0_int8, fnname: "add_0_int8", in: 1, want: 1},
+ test_int8{fn: add_int8_0, fnname: "add_int8_0", in: 1, want: 1},
+ test_int8{fn: add_0_int8, fnname: "add_0_int8", in: 126, want: 126},
+ test_int8{fn: add_int8_0, fnname: "add_int8_0", in: 126, want: 126},
+ test_int8{fn: add_0_int8, fnname: "add_0_int8", in: 127, want: 127},
+ test_int8{fn: add_int8_0, fnname: "add_int8_0", in: 127, want: 127},
+ test_int8{fn: add_1_int8, fnname: "add_1_int8", in: -128, want: -127},
+ test_int8{fn: add_int8_1, fnname: "add_int8_1", in: -128, want: -127},
+ test_int8{fn: add_1_int8, fnname: "add_1_int8", in: -127, want: -126},
+ test_int8{fn: add_int8_1, fnname: "add_int8_1", in: -127, want: -126},
+ test_int8{fn: add_1_int8, fnname: "add_1_int8", in: -1, want: 0},
+ test_int8{fn: add_int8_1, fnname: "add_int8_1", in: -1, want: 0},
+ test_int8{fn: add_1_int8, fnname: "add_1_int8", in: 0, want: 1},
+ test_int8{fn: add_int8_1, fnname: "add_int8_1", in: 0, want: 1},
+ test_int8{fn: add_1_int8, fnname: "add_1_int8", in: 1, want: 2},
+ test_int8{fn: add_int8_1, fnname: "add_int8_1", in: 1, want: 2},
+ test_int8{fn: add_1_int8, fnname: "add_1_int8", in: 126, want: 127},
+ test_int8{fn: add_int8_1, fnname: "add_int8_1", in: 126, want: 127},
+ test_int8{fn: add_1_int8, fnname: "add_1_int8", in: 127, want: -128},
+ test_int8{fn: add_int8_1, fnname: "add_int8_1", in: 127, want: -128},
+ test_int8{fn: add_126_int8, fnname: "add_126_int8", in: -128, want: -2},
+ test_int8{fn: add_int8_126, fnname: "add_int8_126", in: -128, want: -2},
+ test_int8{fn: add_126_int8, fnname: "add_126_int8", in: -127, want: -1},
+ test_int8{fn: add_int8_126, fnname: "add_int8_126", in: -127, want: -1},
+ test_int8{fn: add_126_int8, fnname: "add_126_int8", in: -1, want: 125},
+ test_int8{fn: add_int8_126, fnname: "add_int8_126", in: -1, want: 125},
+ test_int8{fn: add_126_int8, fnname: "add_126_int8", in: 0, want: 126},
+ test_int8{fn: add_int8_126, fnname: "add_int8_126", in: 0, want: 126},
+ test_int8{fn: add_126_int8, fnname: "add_126_int8", in: 1, want: 127},
+ test_int8{fn: add_int8_126, fnname: "add_int8_126", in: 1, want: 127},
+ test_int8{fn: add_126_int8, fnname: "add_126_int8", in: 126, want: -4},
+ test_int8{fn: add_int8_126, fnname: "add_int8_126", in: 126, want: -4},
+ test_int8{fn: add_126_int8, fnname: "add_126_int8", in: 127, want: -3},
+ test_int8{fn: add_int8_126, fnname: "add_int8_126", in: 127, want: -3},
+ test_int8{fn: add_127_int8, fnname: "add_127_int8", in: -128, want: -1},
+ test_int8{fn: add_int8_127, fnname: "add_int8_127", in: -128, want: -1},
+ test_int8{fn: add_127_int8, fnname: "add_127_int8", in: -127, want: 0},
+ test_int8{fn: add_int8_127, fnname: "add_int8_127", in: -127, want: 0},
+ test_int8{fn: add_127_int8, fnname: "add_127_int8", in: -1, want: 126},
+ test_int8{fn: add_int8_127, fnname: "add_int8_127", in: -1, want: 126},
+ test_int8{fn: add_127_int8, fnname: "add_127_int8", in: 0, want: 127},
+ test_int8{fn: add_int8_127, fnname: "add_int8_127", in: 0, want: 127},
+ test_int8{fn: add_127_int8, fnname: "add_127_int8", in: 1, want: -128},
+ test_int8{fn: add_int8_127, fnname: "add_int8_127", in: 1, want: -128},
+ test_int8{fn: add_127_int8, fnname: "add_127_int8", in: 126, want: -3},
+ test_int8{fn: add_int8_127, fnname: "add_int8_127", in: 126, want: -3},
+ test_int8{fn: add_127_int8, fnname: "add_127_int8", in: 127, want: -2},
+ test_int8{fn: add_int8_127, fnname: "add_int8_127", in: 127, want: -2},
+ test_int8{fn: sub_Neg128_int8, fnname: "sub_Neg128_int8", in: -128, want: 0},
+ test_int8{fn: sub_int8_Neg128, fnname: "sub_int8_Neg128", in: -128, want: 0},
+ test_int8{fn: sub_Neg128_int8, fnname: "sub_Neg128_int8", in: -127, want: -1},
+ test_int8{fn: sub_int8_Neg128, fnname: "sub_int8_Neg128", in: -127, want: 1},
+ test_int8{fn: sub_Neg128_int8, fnname: "sub_Neg128_int8", in: -1, want: -127},
+ test_int8{fn: sub_int8_Neg128, fnname: "sub_int8_Neg128", in: -1, want: 127},
+ test_int8{fn: sub_Neg128_int8, fnname: "sub_Neg128_int8", in: 0, want: -128},
+ test_int8{fn: sub_int8_Neg128, fnname: "sub_int8_Neg128", in: 0, want: -128},
+ test_int8{fn: sub_Neg128_int8, fnname: "sub_Neg128_int8", in: 1, want: 127},
+ test_int8{fn: sub_int8_Neg128, fnname: "sub_int8_Neg128", in: 1, want: -127},
+ test_int8{fn: sub_Neg128_int8, fnname: "sub_Neg128_int8", in: 126, want: 2},
+ test_int8{fn: sub_int8_Neg128, fnname: "sub_int8_Neg128", in: 126, want: -2},
+ test_int8{fn: sub_Neg128_int8, fnname: "sub_Neg128_int8", in: 127, want: 1},
+ test_int8{fn: sub_int8_Neg128, fnname: "sub_int8_Neg128", in: 127, want: -1},
+ test_int8{fn: sub_Neg127_int8, fnname: "sub_Neg127_int8", in: -128, want: 1},
+ test_int8{fn: sub_int8_Neg127, fnname: "sub_int8_Neg127", in: -128, want: -1},
+ test_int8{fn: sub_Neg127_int8, fnname: "sub_Neg127_int8", in: -127, want: 0},
+ test_int8{fn: sub_int8_Neg127, fnname: "sub_int8_Neg127", in: -127, want: 0},
+ test_int8{fn: sub_Neg127_int8, fnname: "sub_Neg127_int8", in: -1, want: -126},
+ test_int8{fn: sub_int8_Neg127, fnname: "sub_int8_Neg127", in: -1, want: 126},
+ test_int8{fn: sub_Neg127_int8, fnname: "sub_Neg127_int8", in: 0, want: -127},
+ test_int8{fn: sub_int8_Neg127, fnname: "sub_int8_Neg127", in: 0, want: 127},
+ test_int8{fn: sub_Neg127_int8, fnname: "sub_Neg127_int8", in: 1, want: -128},
+ test_int8{fn: sub_int8_Neg127, fnname: "sub_int8_Neg127", in: 1, want: -128},
+ test_int8{fn: sub_Neg127_int8, fnname: "sub_Neg127_int8", in: 126, want: 3},
+ test_int8{fn: sub_int8_Neg127, fnname: "sub_int8_Neg127", in: 126, want: -3},
+ test_int8{fn: sub_Neg127_int8, fnname: "sub_Neg127_int8", in: 127, want: 2},
+ test_int8{fn: sub_int8_Neg127, fnname: "sub_int8_Neg127", in: 127, want: -2},
+ test_int8{fn: sub_Neg1_int8, fnname: "sub_Neg1_int8", in: -128, want: 127},
+ test_int8{fn: sub_int8_Neg1, fnname: "sub_int8_Neg1", in: -128, want: -127},
+ test_int8{fn: sub_Neg1_int8, fnname: "sub_Neg1_int8", in: -127, want: 126},
+ test_int8{fn: sub_int8_Neg1, fnname: "sub_int8_Neg1", in: -127, want: -126},
+ test_int8{fn: sub_Neg1_int8, fnname: "sub_Neg1_int8", in: -1, want: 0},
+ test_int8{fn: sub_int8_Neg1, fnname: "sub_int8_Neg1", in: -1, want: 0},
+ test_int8{fn: sub_Neg1_int8, fnname: "sub_Neg1_int8", in: 0, want: -1},
+ test_int8{fn: sub_int8_Neg1, fnname: "sub_int8_Neg1", in: 0, want: 1},
+ test_int8{fn: sub_Neg1_int8, fnname: "sub_Neg1_int8", in: 1, want: -2},
+ test_int8{fn: sub_int8_Neg1, fnname: "sub_int8_Neg1", in: 1, want: 2},
+ test_int8{fn: sub_Neg1_int8, fnname: "sub_Neg1_int8", in: 126, want: -127},
+ test_int8{fn: sub_int8_Neg1, fnname: "sub_int8_Neg1", in: 126, want: 127},
+ test_int8{fn: sub_Neg1_int8, fnname: "sub_Neg1_int8", in: 127, want: -128},
+ test_int8{fn: sub_int8_Neg1, fnname: "sub_int8_Neg1", in: 127, want: -128},
+ test_int8{fn: sub_0_int8, fnname: "sub_0_int8", in: -128, want: -128},
+ test_int8{fn: sub_int8_0, fnname: "sub_int8_0", in: -128, want: -128},
+ test_int8{fn: sub_0_int8, fnname: "sub_0_int8", in: -127, want: 127},
+ test_int8{fn: sub_int8_0, fnname: "sub_int8_0", in: -127, want: -127},
+ test_int8{fn: sub_0_int8, fnname: "sub_0_int8", in: -1, want: 1},
+ test_int8{fn: sub_int8_0, fnname: "sub_int8_0", in: -1, want: -1},
+ test_int8{fn: sub_0_int8, fnname: "sub_0_int8", in: 0, want: 0},
+ test_int8{fn: sub_int8_0, fnname: "sub_int8_0", in: 0, want: 0},
+ test_int8{fn: sub_0_int8, fnname: "sub_0_int8", in: 1, want: -1},
+ test_int8{fn: sub_int8_0, fnname: "sub_int8_0", in: 1, want: 1},
+ test_int8{fn: sub_0_int8, fnname: "sub_0_int8", in: 126, want: -126},
+ test_int8{fn: sub_int8_0, fnname: "sub_int8_0", in: 126, want: 126},
+ test_int8{fn: sub_0_int8, fnname: "sub_0_int8", in: 127, want: -127},
+ test_int8{fn: sub_int8_0, fnname: "sub_int8_0", in: 127, want: 127},
+ test_int8{fn: sub_1_int8, fnname: "sub_1_int8", in: -128, want: -127},
+ test_int8{fn: sub_int8_1, fnname: "sub_int8_1", in: -128, want: 127},
+ test_int8{fn: sub_1_int8, fnname: "sub_1_int8", in: -127, want: -128},
+ test_int8{fn: sub_int8_1, fnname: "sub_int8_1", in: -127, want: -128},
+ test_int8{fn: sub_1_int8, fnname: "sub_1_int8", in: -1, want: 2},
+ test_int8{fn: sub_int8_1, fnname: "sub_int8_1", in: -1, want: -2},
+ test_int8{fn: sub_1_int8, fnname: "sub_1_int8", in: 0, want: 1},
+ test_int8{fn: sub_int8_1, fnname: "sub_int8_1", in: 0, want: -1},
+ test_int8{fn: sub_1_int8, fnname: "sub_1_int8", in: 1, want: 0},
+ test_int8{fn: sub_int8_1, fnname: "sub_int8_1", in: 1, want: 0},
+ test_int8{fn: sub_1_int8, fnname: "sub_1_int8", in: 126, want: -125},
+ test_int8{fn: sub_int8_1, fnname: "sub_int8_1", in: 126, want: 125},
+ test_int8{fn: sub_1_int8, fnname: "sub_1_int8", in: 127, want: -126},
+ test_int8{fn: sub_int8_1, fnname: "sub_int8_1", in: 127, want: 126},
+ test_int8{fn: sub_126_int8, fnname: "sub_126_int8", in: -128, want: -2},
+ test_int8{fn: sub_int8_126, fnname: "sub_int8_126", in: -128, want: 2},
+ test_int8{fn: sub_126_int8, fnname: "sub_126_int8", in: -127, want: -3},
+ test_int8{fn: sub_int8_126, fnname: "sub_int8_126", in: -127, want: 3},
+ test_int8{fn: sub_126_int8, fnname: "sub_126_int8", in: -1, want: 127},
+ test_int8{fn: sub_int8_126, fnname: "sub_int8_126", in: -1, want: -127},
+ test_int8{fn: sub_126_int8, fnname: "sub_126_int8", in: 0, want: 126},
+ test_int8{fn: sub_int8_126, fnname: "sub_int8_126", in: 0, want: -126},
+ test_int8{fn: sub_126_int8, fnname: "sub_126_int8", in: 1, want: 125},
+ test_int8{fn: sub_int8_126, fnname: "sub_int8_126", in: 1, want: -125},
+ test_int8{fn: sub_126_int8, fnname: "sub_126_int8", in: 126, want: 0},
+ test_int8{fn: sub_int8_126, fnname: "sub_int8_126", in: 126, want: 0},
+ test_int8{fn: sub_126_int8, fnname: "sub_126_int8", in: 127, want: -1},
+ test_int8{fn: sub_int8_126, fnname: "sub_int8_126", in: 127, want: 1},
+ test_int8{fn: sub_127_int8, fnname: "sub_127_int8", in: -128, want: -1},
+ test_int8{fn: sub_int8_127, fnname: "sub_int8_127", in: -128, want: 1},
+ test_int8{fn: sub_127_int8, fnname: "sub_127_int8", in: -127, want: -2},
+ test_int8{fn: sub_int8_127, fnname: "sub_int8_127", in: -127, want: 2},
+ test_int8{fn: sub_127_int8, fnname: "sub_127_int8", in: -1, want: -128},
+ test_int8{fn: sub_int8_127, fnname: "sub_int8_127", in: -1, want: -128},
+ test_int8{fn: sub_127_int8, fnname: "sub_127_int8", in: 0, want: 127},
+ test_int8{fn: sub_int8_127, fnname: "sub_int8_127", in: 0, want: -127},
+ test_int8{fn: sub_127_int8, fnname: "sub_127_int8", in: 1, want: 126},
+ test_int8{fn: sub_int8_127, fnname: "sub_int8_127", in: 1, want: -126},
+ test_int8{fn: sub_127_int8, fnname: "sub_127_int8", in: 126, want: 1},
+ test_int8{fn: sub_int8_127, fnname: "sub_int8_127", in: 126, want: -1},
+ test_int8{fn: sub_127_int8, fnname: "sub_127_int8", in: 127, want: 0},
+ test_int8{fn: sub_int8_127, fnname: "sub_int8_127", in: 127, want: 0},
+ test_int8{fn: div_Neg128_int8, fnname: "div_Neg128_int8", in: -128, want: 1},
+ test_int8{fn: div_int8_Neg128, fnname: "div_int8_Neg128", in: -128, want: 1},
+ test_int8{fn: div_Neg128_int8, fnname: "div_Neg128_int8", in: -127, want: 1},
+ test_int8{fn: div_int8_Neg128, fnname: "div_int8_Neg128", in: -127, want: 0},
+ test_int8{fn: div_Neg128_int8, fnname: "div_Neg128_int8", in: -1, want: -128},
+ test_int8{fn: div_int8_Neg128, fnname: "div_int8_Neg128", in: -1, want: 0},
+ test_int8{fn: div_int8_Neg128, fnname: "div_int8_Neg128", in: 0, want: 0},
+ test_int8{fn: div_Neg128_int8, fnname: "div_Neg128_int8", in: 1, want: -128},
+ test_int8{fn: div_int8_Neg128, fnname: "div_int8_Neg128", in: 1, want: 0},
+ test_int8{fn: div_Neg128_int8, fnname: "div_Neg128_int8", in: 126, want: -1},
+ test_int8{fn: div_int8_Neg128, fnname: "div_int8_Neg128", in: 126, want: 0},
+ test_int8{fn: div_Neg128_int8, fnname: "div_Neg128_int8", in: 127, want: -1},
+ test_int8{fn: div_int8_Neg128, fnname: "div_int8_Neg128", in: 127, want: 0},
+ test_int8{fn: div_Neg127_int8, fnname: "div_Neg127_int8", in: -128, want: 0},
+ test_int8{fn: div_int8_Neg127, fnname: "div_int8_Neg127", in: -128, want: 1},
+ test_int8{fn: div_Neg127_int8, fnname: "div_Neg127_int8", in: -127, want: 1},
+ test_int8{fn: div_int8_Neg127, fnname: "div_int8_Neg127", in: -127, want: 1},
+ test_int8{fn: div_Neg127_int8, fnname: "div_Neg127_int8", in: -1, want: 127},
+ test_int8{fn: div_int8_Neg127, fnname: "div_int8_Neg127", in: -1, want: 0},
+ test_int8{fn: div_int8_Neg127, fnname: "div_int8_Neg127", in: 0, want: 0},
+ test_int8{fn: div_Neg127_int8, fnname: "div_Neg127_int8", in: 1, want: -127},
+ test_int8{fn: div_int8_Neg127, fnname: "div_int8_Neg127", in: 1, want: 0},
+ test_int8{fn: div_Neg127_int8, fnname: "div_Neg127_int8", in: 126, want: -1},
+ test_int8{fn: div_int8_Neg127, fnname: "div_int8_Neg127", in: 126, want: 0},
+ test_int8{fn: div_Neg127_int8, fnname: "div_Neg127_int8", in: 127, want: -1},
+ test_int8{fn: div_int8_Neg127, fnname: "div_int8_Neg127", in: 127, want: -1},
+ test_int8{fn: div_Neg1_int8, fnname: "div_Neg1_int8", in: -128, want: 0},
+ test_int8{fn: div_int8_Neg1, fnname: "div_int8_Neg1", in: -128, want: -128},
+ test_int8{fn: div_Neg1_int8, fnname: "div_Neg1_int8", in: -127, want: 0},
+ test_int8{fn: div_int8_Neg1, fnname: "div_int8_Neg1", in: -127, want: 127},
+ test_int8{fn: div_Neg1_int8, fnname: "div_Neg1_int8", in: -1, want: 1},
+ test_int8{fn: div_int8_Neg1, fnname: "div_int8_Neg1", in: -1, want: 1},
+ test_int8{fn: div_int8_Neg1, fnname: "div_int8_Neg1", in: 0, want: 0},
+ test_int8{fn: div_Neg1_int8, fnname: "div_Neg1_int8", in: 1, want: -1},
+ test_int8{fn: div_int8_Neg1, fnname: "div_int8_Neg1", in: 1, want: -1},
+ test_int8{fn: div_Neg1_int8, fnname: "div_Neg1_int8", in: 126, want: 0},
+ test_int8{fn: div_int8_Neg1, fnname: "div_int8_Neg1", in: 126, want: -126},
+ test_int8{fn: div_Neg1_int8, fnname: "div_Neg1_int8", in: 127, want: 0},
+ test_int8{fn: div_int8_Neg1, fnname: "div_int8_Neg1", in: 127, want: -127},
+ test_int8{fn: div_0_int8, fnname: "div_0_int8", in: -128, want: 0},
+ test_int8{fn: div_0_int8, fnname: "div_0_int8", in: -127, want: 0},
+ test_int8{fn: div_0_int8, fnname: "div_0_int8", in: -1, want: 0},
+ test_int8{fn: div_0_int8, fnname: "div_0_int8", in: 1, want: 0},
+ test_int8{fn: div_0_int8, fnname: "div_0_int8", in: 126, want: 0},
+ test_int8{fn: div_0_int8, fnname: "div_0_int8", in: 127, want: 0},
+ test_int8{fn: div_1_int8, fnname: "div_1_int8", in: -128, want: 0},
+ test_int8{fn: div_int8_1, fnname: "div_int8_1", in: -128, want: -128},
+ test_int8{fn: div_1_int8, fnname: "div_1_int8", in: -127, want: 0},
+ test_int8{fn: div_int8_1, fnname: "div_int8_1", in: -127, want: -127},
+ test_int8{fn: div_1_int8, fnname: "div_1_int8", in: -1, want: -1},
+ test_int8{fn: div_int8_1, fnname: "div_int8_1", in: -1, want: -1},
+ test_int8{fn: div_int8_1, fnname: "div_int8_1", in: 0, want: 0},
+ test_int8{fn: div_1_int8, fnname: "div_1_int8", in: 1, want: 1},
+ test_int8{fn: div_int8_1, fnname: "div_int8_1", in: 1, want: 1},
+ test_int8{fn: div_1_int8, fnname: "div_1_int8", in: 126, want: 0},
+ test_int8{fn: div_int8_1, fnname: "div_int8_1", in: 126, want: 126},
+ test_int8{fn: div_1_int8, fnname: "div_1_int8", in: 127, want: 0},
+ test_int8{fn: div_int8_1, fnname: "div_int8_1", in: 127, want: 127},
+ test_int8{fn: div_126_int8, fnname: "div_126_int8", in: -128, want: 0},
+ test_int8{fn: div_int8_126, fnname: "div_int8_126", in: -128, want: -1},
+ test_int8{fn: div_126_int8, fnname: "div_126_int8", in: -127, want: 0},
+ test_int8{fn: div_int8_126, fnname: "div_int8_126", in: -127, want: -1},
+ test_int8{fn: div_126_int8, fnname: "div_126_int8", in: -1, want: -126},
+ test_int8{fn: div_int8_126, fnname: "div_int8_126", in: -1, want: 0},
+ test_int8{fn: div_int8_126, fnname: "div_int8_126", in: 0, want: 0},
+ test_int8{fn: div_126_int8, fnname: "div_126_int8", in: 1, want: 126},
+ test_int8{fn: div_int8_126, fnname: "div_int8_126", in: 1, want: 0},
+ test_int8{fn: div_126_int8, fnname: "div_126_int8", in: 126, want: 1},
+ test_int8{fn: div_int8_126, fnname: "div_int8_126", in: 126, want: 1},
+ test_int8{fn: div_126_int8, fnname: "div_126_int8", in: 127, want: 0},
+ test_int8{fn: div_int8_126, fnname: "div_int8_126", in: 127, want: 1},
+ test_int8{fn: div_127_int8, fnname: "div_127_int8", in: -128, want: 0},
+ test_int8{fn: div_int8_127, fnname: "div_int8_127", in: -128, want: -1},
+ test_int8{fn: div_127_int8, fnname: "div_127_int8", in: -127, want: -1},
+ test_int8{fn: div_int8_127, fnname: "div_int8_127", in: -127, want: -1},
+ test_int8{fn: div_127_int8, fnname: "div_127_int8", in: -1, want: -127},
+ test_int8{fn: div_int8_127, fnname: "div_int8_127", in: -1, want: 0},
+ test_int8{fn: div_int8_127, fnname: "div_int8_127", in: 0, want: 0},
+ test_int8{fn: div_127_int8, fnname: "div_127_int8", in: 1, want: 127},
+ test_int8{fn: div_int8_127, fnname: "div_int8_127", in: 1, want: 0},
+ test_int8{fn: div_127_int8, fnname: "div_127_int8", in: 126, want: 1},
+ test_int8{fn: div_int8_127, fnname: "div_int8_127", in: 126, want: 0},
+ test_int8{fn: div_127_int8, fnname: "div_127_int8", in: 127, want: 1},
+ test_int8{fn: div_int8_127, fnname: "div_int8_127", in: 127, want: 1},
+ test_int8{fn: mul_Neg128_int8, fnname: "mul_Neg128_int8", in: -128, want: 0},
+ test_int8{fn: mul_int8_Neg128, fnname: "mul_int8_Neg128", in: -128, want: 0},
+ test_int8{fn: mul_Neg128_int8, fnname: "mul_Neg128_int8", in: -127, want: -128},
+ test_int8{fn: mul_int8_Neg128, fnname: "mul_int8_Neg128", in: -127, want: -128},
+ test_int8{fn: mul_Neg128_int8, fnname: "mul_Neg128_int8", in: -1, want: -128},
+ test_int8{fn: mul_int8_Neg128, fnname: "mul_int8_Neg128", in: -1, want: -128},
+ test_int8{fn: mul_Neg128_int8, fnname: "mul_Neg128_int8", in: 0, want: 0},
+ test_int8{fn: mul_int8_Neg128, fnname: "mul_int8_Neg128", in: 0, want: 0},
+ test_int8{fn: mul_Neg128_int8, fnname: "mul_Neg128_int8", in: 1, want: -128},
+ test_int8{fn: mul_int8_Neg128, fnname: "mul_int8_Neg128", in: 1, want: -128},
+ test_int8{fn: mul_Neg128_int8, fnname: "mul_Neg128_int8", in: 126, want: 0},
+ test_int8{fn: mul_int8_Neg128, fnname: "mul_int8_Neg128", in: 126, want: 0},
+ test_int8{fn: mul_Neg128_int8, fnname: "mul_Neg128_int8", in: 127, want: -128},
+ test_int8{fn: mul_int8_Neg128, fnname: "mul_int8_Neg128", in: 127, want: -128},
+ test_int8{fn: mul_Neg127_int8, fnname: "mul_Neg127_int8", in: -128, want: -128},
+ test_int8{fn: mul_int8_Neg127, fnname: "mul_int8_Neg127", in: -128, want: -128},
+ test_int8{fn: mul_Neg127_int8, fnname: "mul_Neg127_int8", in: -127, want: 1},
+ test_int8{fn: mul_int8_Neg127, fnname: "mul_int8_Neg127", in: -127, want: 1},
+ test_int8{fn: mul_Neg127_int8, fnname: "mul_Neg127_int8", in: -1, want: 127},
+ test_int8{fn: mul_int8_Neg127, fnname: "mul_int8_Neg127", in: -1, want: 127},
+ test_int8{fn: mul_Neg127_int8, fnname: "mul_Neg127_int8", in: 0, want: 0},
+ test_int8{fn: mul_int8_Neg127, fnname: "mul_int8_Neg127", in: 0, want: 0},
+ test_int8{fn: mul_Neg127_int8, fnname: "mul_Neg127_int8", in: 1, want: -127},
+ test_int8{fn: mul_int8_Neg127, fnname: "mul_int8_Neg127", in: 1, want: -127},
+ test_int8{fn: mul_Neg127_int8, fnname: "mul_Neg127_int8", in: 126, want: 126},
+ test_int8{fn: mul_int8_Neg127, fnname: "mul_int8_Neg127", in: 126, want: 126},
+ test_int8{fn: mul_Neg127_int8, fnname: "mul_Neg127_int8", in: 127, want: -1},
+ test_int8{fn: mul_int8_Neg127, fnname: "mul_int8_Neg127", in: 127, want: -1},
+ test_int8{fn: mul_Neg1_int8, fnname: "mul_Neg1_int8", in: -128, want: -128},
+ test_int8{fn: mul_int8_Neg1, fnname: "mul_int8_Neg1", in: -128, want: -128},
+ test_int8{fn: mul_Neg1_int8, fnname: "mul_Neg1_int8", in: -127, want: 127},
+ test_int8{fn: mul_int8_Neg1, fnname: "mul_int8_Neg1", in: -127, want: 127},
+ test_int8{fn: mul_Neg1_int8, fnname: "mul_Neg1_int8", in: -1, want: 1},
+ test_int8{fn: mul_int8_Neg1, fnname: "mul_int8_Neg1", in: -1, want: 1},
+ test_int8{fn: mul_Neg1_int8, fnname: "mul_Neg1_int8", in: 0, want: 0},
+ test_int8{fn: mul_int8_Neg1, fnname: "mul_int8_Neg1", in: 0, want: 0},
+ test_int8{fn: mul_Neg1_int8, fnname: "mul_Neg1_int8", in: 1, want: -1},
+ test_int8{fn: mul_int8_Neg1, fnname: "mul_int8_Neg1", in: 1, want: -1},
+ test_int8{fn: mul_Neg1_int8, fnname: "mul_Neg1_int8", in: 126, want: -126},
+ test_int8{fn: mul_int8_Neg1, fnname: "mul_int8_Neg1", in: 126, want: -126},
+ test_int8{fn: mul_Neg1_int8, fnname: "mul_Neg1_int8", in: 127, want: -127},
+ test_int8{fn: mul_int8_Neg1, fnname: "mul_int8_Neg1", in: 127, want: -127},
+ test_int8{fn: mul_0_int8, fnname: "mul_0_int8", in: -128, want: 0},
+ test_int8{fn: mul_int8_0, fnname: "mul_int8_0", in: -128, want: 0},
+ test_int8{fn: mul_0_int8, fnname: "mul_0_int8", in: -127, want: 0},
+ test_int8{fn: mul_int8_0, fnname: "mul_int8_0", in: -127, want: 0},
+ test_int8{fn: mul_0_int8, fnname: "mul_0_int8", in: -1, want: 0},
+ test_int8{fn: mul_int8_0, fnname: "mul_int8_0", in: -1, want: 0},
+ test_int8{fn: mul_0_int8, fnname: "mul_0_int8", in: 0, want: 0},
+ test_int8{fn: mul_int8_0, fnname: "mul_int8_0", in: 0, want: 0},
+ test_int8{fn: mul_0_int8, fnname: "mul_0_int8", in: 1, want: 0},
+ test_int8{fn: mul_int8_0, fnname: "mul_int8_0", in: 1, want: 0},
+ test_int8{fn: mul_0_int8, fnname: "mul_0_int8", in: 126, want: 0},
+ test_int8{fn: mul_int8_0, fnname: "mul_int8_0", in: 126, want: 0},
+ test_int8{fn: mul_0_int8, fnname: "mul_0_int8", in: 127, want: 0},
+ test_int8{fn: mul_int8_0, fnname: "mul_int8_0", in: 127, want: 0},
+ test_int8{fn: mul_1_int8, fnname: "mul_1_int8", in: -128, want: -128},
+ test_int8{fn: mul_int8_1, fnname: "mul_int8_1", in: -128, want: -128},
+ test_int8{fn: mul_1_int8, fnname: "mul_1_int8", in: -127, want: -127},
+ test_int8{fn: mul_int8_1, fnname: "mul_int8_1", in: -127, want: -127},
+ test_int8{fn: mul_1_int8, fnname: "mul_1_int8", in: -1, want: -1},
+ test_int8{fn: mul_int8_1, fnname: "mul_int8_1", in: -1, want: -1},
+ test_int8{fn: mul_1_int8, fnname: "mul_1_int8", in: 0, want: 0},
+ test_int8{fn: mul_int8_1, fnname: "mul_int8_1", in: 0, want: 0},
+ test_int8{fn: mul_1_int8, fnname: "mul_1_int8", in: 1, want: 1},
+ test_int8{fn: mul_int8_1, fnname: "mul_int8_1", in: 1, want: 1},
+ test_int8{fn: mul_1_int8, fnname: "mul_1_int8", in: 126, want: 126},
+ test_int8{fn: mul_int8_1, fnname: "mul_int8_1", in: 126, want: 126},
+ test_int8{fn: mul_1_int8, fnname: "mul_1_int8", in: 127, want: 127},
+ test_int8{fn: mul_int8_1, fnname: "mul_int8_1", in: 127, want: 127},
+ test_int8{fn: mul_126_int8, fnname: "mul_126_int8", in: -128, want: 0},
+ test_int8{fn: mul_int8_126, fnname: "mul_int8_126", in: -128, want: 0},
+ test_int8{fn: mul_126_int8, fnname: "mul_126_int8", in: -127, want: 126},
+ test_int8{fn: mul_int8_126, fnname: "mul_int8_126", in: -127, want: 126},
+ test_int8{fn: mul_126_int8, fnname: "mul_126_int8", in: -1, want: -126},
+ test_int8{fn: mul_int8_126, fnname: "mul_int8_126", in: -1, want: -126},
+ test_int8{fn: mul_126_int8, fnname: "mul_126_int8", in: 0, want: 0},
+ test_int8{fn: mul_int8_126, fnname: "mul_int8_126", in: 0, want: 0},
+ test_int8{fn: mul_126_int8, fnname: "mul_126_int8", in: 1, want: 126},
+ test_int8{fn: mul_int8_126, fnname: "mul_int8_126", in: 1, want: 126},
+ test_int8{fn: mul_126_int8, fnname: "mul_126_int8", in: 126, want: 4},
+ test_int8{fn: mul_int8_126, fnname: "mul_int8_126", in: 126, want: 4},
+ test_int8{fn: mul_126_int8, fnname: "mul_126_int8", in: 127, want: -126},
+ test_int8{fn: mul_int8_126, fnname: "mul_int8_126", in: 127, want: -126},
+ test_int8{fn: mul_127_int8, fnname: "mul_127_int8", in: -128, want: -128},
+ test_int8{fn: mul_int8_127, fnname: "mul_int8_127", in: -128, want: -128},
+ test_int8{fn: mul_127_int8, fnname: "mul_127_int8", in: -127, want: -1},
+ test_int8{fn: mul_int8_127, fnname: "mul_int8_127", in: -127, want: -1},
+ test_int8{fn: mul_127_int8, fnname: "mul_127_int8", in: -1, want: -127},
+ test_int8{fn: mul_int8_127, fnname: "mul_int8_127", in: -1, want: -127},
+ test_int8{fn: mul_127_int8, fnname: "mul_127_int8", in: 0, want: 0},
+ test_int8{fn: mul_int8_127, fnname: "mul_int8_127", in: 0, want: 0},
+ test_int8{fn: mul_127_int8, fnname: "mul_127_int8", in: 1, want: 127},
+ test_int8{fn: mul_int8_127, fnname: "mul_int8_127", in: 1, want: 127},
+ test_int8{fn: mul_127_int8, fnname: "mul_127_int8", in: 126, want: -126},
+ test_int8{fn: mul_int8_127, fnname: "mul_int8_127", in: 126, want: -126},
+ test_int8{fn: mul_127_int8, fnname: "mul_127_int8", in: 127, want: 1},
+ test_int8{fn: mul_int8_127, fnname: "mul_int8_127", in: 127, want: 1},
+ test_int8{fn: mod_Neg128_int8, fnname: "mod_Neg128_int8", in: -128, want: 0},
+ test_int8{fn: mod_int8_Neg128, fnname: "mod_int8_Neg128", in: -128, want: 0},
+ test_int8{fn: mod_Neg128_int8, fnname: "mod_Neg128_int8", in: -127, want: -1},
+ test_int8{fn: mod_int8_Neg128, fnname: "mod_int8_Neg128", in: -127, want: -127},
+ test_int8{fn: mod_Neg128_int8, fnname: "mod_Neg128_int8", in: -1, want: 0},
+ test_int8{fn: mod_int8_Neg128, fnname: "mod_int8_Neg128", in: -1, want: -1},
+ test_int8{fn: mod_int8_Neg128, fnname: "mod_int8_Neg128", in: 0, want: 0},
+ test_int8{fn: mod_Neg128_int8, fnname: "mod_Neg128_int8", in: 1, want: 0},
+ test_int8{fn: mod_int8_Neg128, fnname: "mod_int8_Neg128", in: 1, want: 1},
+ test_int8{fn: mod_Neg128_int8, fnname: "mod_Neg128_int8", in: 126, want: -2},
+ test_int8{fn: mod_int8_Neg128, fnname: "mod_int8_Neg128", in: 126, want: 126},
+ test_int8{fn: mod_Neg128_int8, fnname: "mod_Neg128_int8", in: 127, want: -1},
+ test_int8{fn: mod_int8_Neg128, fnname: "mod_int8_Neg128", in: 127, want: 127},
+ test_int8{fn: mod_Neg127_int8, fnname: "mod_Neg127_int8", in: -128, want: -127},
+ test_int8{fn: mod_int8_Neg127, fnname: "mod_int8_Neg127", in: -128, want: -1},
+ test_int8{fn: mod_Neg127_int8, fnname: "mod_Neg127_int8", in: -127, want: 0},
+ test_int8{fn: mod_int8_Neg127, fnname: "mod_int8_Neg127", in: -127, want: 0},
+ test_int8{fn: mod_Neg127_int8, fnname: "mod_Neg127_int8", in: -1, want: 0},
+ test_int8{fn: mod_int8_Neg127, fnname: "mod_int8_Neg127", in: -1, want: -1},
+ test_int8{fn: mod_int8_Neg127, fnname: "mod_int8_Neg127", in: 0, want: 0},
+ test_int8{fn: mod_Neg127_int8, fnname: "mod_Neg127_int8", in: 1, want: 0},
+ test_int8{fn: mod_int8_Neg127, fnname: "mod_int8_Neg127", in: 1, want: 1},
+ test_int8{fn: mod_Neg127_int8, fnname: "mod_Neg127_int8", in: 126, want: -1},
+ test_int8{fn: mod_int8_Neg127, fnname: "mod_int8_Neg127", in: 126, want: 126},
+ test_int8{fn: mod_Neg127_int8, fnname: "mod_Neg127_int8", in: 127, want: 0},
+ test_int8{fn: mod_int8_Neg127, fnname: "mod_int8_Neg127", in: 127, want: 0},
+ test_int8{fn: mod_Neg1_int8, fnname: "mod_Neg1_int8", in: -128, want: -1},
+ test_int8{fn: mod_int8_Neg1, fnname: "mod_int8_Neg1", in: -128, want: 0},
+ test_int8{fn: mod_Neg1_int8, fnname: "mod_Neg1_int8", in: -127, want: -1},
+ test_int8{fn: mod_int8_Neg1, fnname: "mod_int8_Neg1", in: -127, want: 0},
+ test_int8{fn: mod_Neg1_int8, fnname: "mod_Neg1_int8", in: -1, want: 0},
+ test_int8{fn: mod_int8_Neg1, fnname: "mod_int8_Neg1", in: -1, want: 0},
+ test_int8{fn: mod_int8_Neg1, fnname: "mod_int8_Neg1", in: 0, want: 0},
+ test_int8{fn: mod_Neg1_int8, fnname: "mod_Neg1_int8", in: 1, want: 0},
+ test_int8{fn: mod_int8_Neg1, fnname: "mod_int8_Neg1", in: 1, want: 0},
+ test_int8{fn: mod_Neg1_int8, fnname: "mod_Neg1_int8", in: 126, want: -1},
+ test_int8{fn: mod_int8_Neg1, fnname: "mod_int8_Neg1", in: 126, want: 0},
+ test_int8{fn: mod_Neg1_int8, fnname: "mod_Neg1_int8", in: 127, want: -1},
+ test_int8{fn: mod_int8_Neg1, fnname: "mod_int8_Neg1", in: 127, want: 0},
+ test_int8{fn: mod_0_int8, fnname: "mod_0_int8", in: -128, want: 0},
+ test_int8{fn: mod_0_int8, fnname: "mod_0_int8", in: -127, want: 0},
+ test_int8{fn: mod_0_int8, fnname: "mod_0_int8", in: -1, want: 0},
+ test_int8{fn: mod_0_int8, fnname: "mod_0_int8", in: 1, want: 0},
+ test_int8{fn: mod_0_int8, fnname: "mod_0_int8", in: 126, want: 0},
+ test_int8{fn: mod_0_int8, fnname: "mod_0_int8", in: 127, want: 0},
+ test_int8{fn: mod_1_int8, fnname: "mod_1_int8", in: -128, want: 1},
+ test_int8{fn: mod_int8_1, fnname: "mod_int8_1", in: -128, want: 0},
+ test_int8{fn: mod_1_int8, fnname: "mod_1_int8", in: -127, want: 1},
+ test_int8{fn: mod_int8_1, fnname: "mod_int8_1", in: -127, want: 0},
+ test_int8{fn: mod_1_int8, fnname: "mod_1_int8", in: -1, want: 0},
+ test_int8{fn: mod_int8_1, fnname: "mod_int8_1", in: -1, want: 0},
+ test_int8{fn: mod_int8_1, fnname: "mod_int8_1", in: 0, want: 0},
+ test_int8{fn: mod_1_int8, fnname: "mod_1_int8", in: 1, want: 0},
+ test_int8{fn: mod_int8_1, fnname: "mod_int8_1", in: 1, want: 0},
+ test_int8{fn: mod_1_int8, fnname: "mod_1_int8", in: 126, want: 1},
+ test_int8{fn: mod_int8_1, fnname: "mod_int8_1", in: 126, want: 0},
+ test_int8{fn: mod_1_int8, fnname: "mod_1_int8", in: 127, want: 1},
+ test_int8{fn: mod_int8_1, fnname: "mod_int8_1", in: 127, want: 0},
+ test_int8{fn: mod_126_int8, fnname: "mod_126_int8", in: -128, want: 126},
+ test_int8{fn: mod_int8_126, fnname: "mod_int8_126", in: -128, want: -2},
+ test_int8{fn: mod_126_int8, fnname: "mod_126_int8", in: -127, want: 126},
+ test_int8{fn: mod_int8_126, fnname: "mod_int8_126", in: -127, want: -1},
+ test_int8{fn: mod_126_int8, fnname: "mod_126_int8", in: -1, want: 0},
+ test_int8{fn: mod_int8_126, fnname: "mod_int8_126", in: -1, want: -1},
+ test_int8{fn: mod_int8_126, fnname: "mod_int8_126", in: 0, want: 0},
+ test_int8{fn: mod_126_int8, fnname: "mod_126_int8", in: 1, want: 0},
+ test_int8{fn: mod_int8_126, fnname: "mod_int8_126", in: 1, want: 1},
+ test_int8{fn: mod_126_int8, fnname: "mod_126_int8", in: 126, want: 0},
+ test_int8{fn: mod_int8_126, fnname: "mod_int8_126", in: 126, want: 0},
+ test_int8{fn: mod_126_int8, fnname: "mod_126_int8", in: 127, want: 126},
+ test_int8{fn: mod_int8_126, fnname: "mod_int8_126", in: 127, want: 1},
+ test_int8{fn: mod_127_int8, fnname: "mod_127_int8", in: -128, want: 127},
+ test_int8{fn: mod_int8_127, fnname: "mod_int8_127", in: -128, want: -1},
+ test_int8{fn: mod_127_int8, fnname: "mod_127_int8", in: -127, want: 0},
+ test_int8{fn: mod_int8_127, fnname: "mod_int8_127", in: -127, want: 0},
+ test_int8{fn: mod_127_int8, fnname: "mod_127_int8", in: -1, want: 0},
+ test_int8{fn: mod_int8_127, fnname: "mod_int8_127", in: -1, want: -1},
+ test_int8{fn: mod_int8_127, fnname: "mod_int8_127", in: 0, want: 0},
+ test_int8{fn: mod_127_int8, fnname: "mod_127_int8", in: 1, want: 0},
+ test_int8{fn: mod_int8_127, fnname: "mod_int8_127", in: 1, want: 1},
+ test_int8{fn: mod_127_int8, fnname: "mod_127_int8", in: 126, want: 1},
+ test_int8{fn: mod_int8_127, fnname: "mod_int8_127", in: 126, want: 126},
+ test_int8{fn: mod_127_int8, fnname: "mod_127_int8", in: 127, want: 0},
+ test_int8{fn: mod_int8_127, fnname: "mod_int8_127", in: 127, want: 0},
+ test_int8{fn: and_Neg128_int8, fnname: "and_Neg128_int8", in: -128, want: -128},
+ test_int8{fn: and_int8_Neg128, fnname: "and_int8_Neg128", in: -128, want: -128},
+ test_int8{fn: and_Neg128_int8, fnname: "and_Neg128_int8", in: -127, want: -128},
+ test_int8{fn: and_int8_Neg128, fnname: "and_int8_Neg128", in: -127, want: -128},
+ test_int8{fn: and_Neg128_int8, fnname: "and_Neg128_int8", in: -1, want: -128},
+ test_int8{fn: and_int8_Neg128, fnname: "and_int8_Neg128", in: -1, want: -128},
+ test_int8{fn: and_Neg128_int8, fnname: "and_Neg128_int8", in: 0, want: 0},
+ test_int8{fn: and_int8_Neg128, fnname: "and_int8_Neg128", in: 0, want: 0},
+ test_int8{fn: and_Neg128_int8, fnname: "and_Neg128_int8", in: 1, want: 0},
+ test_int8{fn: and_int8_Neg128, fnname: "and_int8_Neg128", in: 1, want: 0},
+ test_int8{fn: and_Neg128_int8, fnname: "and_Neg128_int8", in: 126, want: 0},
+ test_int8{fn: and_int8_Neg128, fnname: "and_int8_Neg128", in: 126, want: 0},
+ test_int8{fn: and_Neg128_int8, fnname: "and_Neg128_int8", in: 127, want: 0},
+ test_int8{fn: and_int8_Neg128, fnname: "and_int8_Neg128", in: 127, want: 0},
+ test_int8{fn: and_Neg127_int8, fnname: "and_Neg127_int8", in: -128, want: -128},
+ test_int8{fn: and_int8_Neg127, fnname: "and_int8_Neg127", in: -128, want: -128},
+ test_int8{fn: and_Neg127_int8, fnname: "and_Neg127_int8", in: -127, want: -127},
+ test_int8{fn: and_int8_Neg127, fnname: "and_int8_Neg127", in: -127, want: -127},
+ test_int8{fn: and_Neg127_int8, fnname: "and_Neg127_int8", in: -1, want: -127},
+ test_int8{fn: and_int8_Neg127, fnname: "and_int8_Neg127", in: -1, want: -127},
+ test_int8{fn: and_Neg127_int8, fnname: "and_Neg127_int8", in: 0, want: 0},
+ test_int8{fn: and_int8_Neg127, fnname: "and_int8_Neg127", in: 0, want: 0},
+ test_int8{fn: and_Neg127_int8, fnname: "and_Neg127_int8", in: 1, want: 1},
+ test_int8{fn: and_int8_Neg127, fnname: "and_int8_Neg127", in: 1, want: 1},
+ test_int8{fn: and_Neg127_int8, fnname: "and_Neg127_int8", in: 126, want: 0},
+ test_int8{fn: and_int8_Neg127, fnname: "and_int8_Neg127", in: 126, want: 0},
+ test_int8{fn: and_Neg127_int8, fnname: "and_Neg127_int8", in: 127, want: 1},
+ test_int8{fn: and_int8_Neg127, fnname: "and_int8_Neg127", in: 127, want: 1},
+ test_int8{fn: and_Neg1_int8, fnname: "and_Neg1_int8", in: -128, want: -128},
+ test_int8{fn: and_int8_Neg1, fnname: "and_int8_Neg1", in: -128, want: -128},
+ test_int8{fn: and_Neg1_int8, fnname: "and_Neg1_int8", in: -127, want: -127},
+ test_int8{fn: and_int8_Neg1, fnname: "and_int8_Neg1", in: -127, want: -127},
+ test_int8{fn: and_Neg1_int8, fnname: "and_Neg1_int8", in: -1, want: -1},
+ test_int8{fn: and_int8_Neg1, fnname: "and_int8_Neg1", in: -1, want: -1},
+ test_int8{fn: and_Neg1_int8, fnname: "and_Neg1_int8", in: 0, want: 0},
+ test_int8{fn: and_int8_Neg1, fnname: "and_int8_Neg1", in: 0, want: 0},
+ test_int8{fn: and_Neg1_int8, fnname: "and_Neg1_int8", in: 1, want: 1},
+ test_int8{fn: and_int8_Neg1, fnname: "and_int8_Neg1", in: 1, want: 1},
+ test_int8{fn: and_Neg1_int8, fnname: "and_Neg1_int8", in: 126, want: 126},
+ test_int8{fn: and_int8_Neg1, fnname: "and_int8_Neg1", in: 126, want: 126},
+ test_int8{fn: and_Neg1_int8, fnname: "and_Neg1_int8", in: 127, want: 127},
+ test_int8{fn: and_int8_Neg1, fnname: "and_int8_Neg1", in: 127, want: 127},
+ test_int8{fn: and_0_int8, fnname: "and_0_int8", in: -128, want: 0},
+ test_int8{fn: and_int8_0, fnname: "and_int8_0", in: -128, want: 0},
+ test_int8{fn: and_0_int8, fnname: "and_0_int8", in: -127, want: 0},
+ test_int8{fn: and_int8_0, fnname: "and_int8_0", in: -127, want: 0},
+ test_int8{fn: and_0_int8, fnname: "and_0_int8", in: -1, want: 0},
+ test_int8{fn: and_int8_0, fnname: "and_int8_0", in: -1, want: 0},
+ test_int8{fn: and_0_int8, fnname: "and_0_int8", in: 0, want: 0},
+ test_int8{fn: and_int8_0, fnname: "and_int8_0", in: 0, want: 0},
+ test_int8{fn: and_0_int8, fnname: "and_0_int8", in: 1, want: 0},
+ test_int8{fn: and_int8_0, fnname: "and_int8_0", in: 1, want: 0},
+ test_int8{fn: and_0_int8, fnname: "and_0_int8", in: 126, want: 0},
+ test_int8{fn: and_int8_0, fnname: "and_int8_0", in: 126, want: 0},
+ test_int8{fn: and_0_int8, fnname: "and_0_int8", in: 127, want: 0},
+ test_int8{fn: and_int8_0, fnname: "and_int8_0", in: 127, want: 0},
+ test_int8{fn: and_1_int8, fnname: "and_1_int8", in: -128, want: 0},
+ test_int8{fn: and_int8_1, fnname: "and_int8_1", in: -128, want: 0},
+ test_int8{fn: and_1_int8, fnname: "and_1_int8", in: -127, want: 1},
+ test_int8{fn: and_int8_1, fnname: "and_int8_1", in: -127, want: 1},
+ test_int8{fn: and_1_int8, fnname: "and_1_int8", in: -1, want: 1},
+ test_int8{fn: and_int8_1, fnname: "and_int8_1", in: -1, want: 1},
+ test_int8{fn: and_1_int8, fnname: "and_1_int8", in: 0, want: 0},
+ test_int8{fn: and_int8_1, fnname: "and_int8_1", in: 0, want: 0},
+ test_int8{fn: and_1_int8, fnname: "and_1_int8", in: 1, want: 1},
+ test_int8{fn: and_int8_1, fnname: "and_int8_1", in: 1, want: 1},
+ test_int8{fn: and_1_int8, fnname: "and_1_int8", in: 126, want: 0},
+ test_int8{fn: and_int8_1, fnname: "and_int8_1", in: 126, want: 0},
+ test_int8{fn: and_1_int8, fnname: "and_1_int8", in: 127, want: 1},
+ test_int8{fn: and_int8_1, fnname: "and_int8_1", in: 127, want: 1},
+ test_int8{fn: and_126_int8, fnname: "and_126_int8", in: -128, want: 0},
+ test_int8{fn: and_int8_126, fnname: "and_int8_126", in: -128, want: 0},
+ test_int8{fn: and_126_int8, fnname: "and_126_int8", in: -127, want: 0},
+ test_int8{fn: and_int8_126, fnname: "and_int8_126", in: -127, want: 0},
+ test_int8{fn: and_126_int8, fnname: "and_126_int8", in: -1, want: 126},
+ test_int8{fn: and_int8_126, fnname: "and_int8_126", in: -1, want: 126},
+ test_int8{fn: and_126_int8, fnname: "and_126_int8", in: 0, want: 0},
+ test_int8{fn: and_int8_126, fnname: "and_int8_126", in: 0, want: 0},
+ test_int8{fn: and_126_int8, fnname: "and_126_int8", in: 1, want: 0},
+ test_int8{fn: and_int8_126, fnname: "and_int8_126", in: 1, want: 0},
+ test_int8{fn: and_126_int8, fnname: "and_126_int8", in: 126, want: 126},
+ test_int8{fn: and_int8_126, fnname: "and_int8_126", in: 126, want: 126},
+ test_int8{fn: and_126_int8, fnname: "and_126_int8", in: 127, want: 126},
+ test_int8{fn: and_int8_126, fnname: "and_int8_126", in: 127, want: 126},
+ test_int8{fn: and_127_int8, fnname: "and_127_int8", in: -128, want: 0},
+ test_int8{fn: and_int8_127, fnname: "and_int8_127", in: -128, want: 0},
+ test_int8{fn: and_127_int8, fnname: "and_127_int8", in: -127, want: 1},
+ test_int8{fn: and_int8_127, fnname: "and_int8_127", in: -127, want: 1},
+ test_int8{fn: and_127_int8, fnname: "and_127_int8", in: -1, want: 127},
+ test_int8{fn: and_int8_127, fnname: "and_int8_127", in: -1, want: 127},
+ test_int8{fn: and_127_int8, fnname: "and_127_int8", in: 0, want: 0},
+ test_int8{fn: and_int8_127, fnname: "and_int8_127", in: 0, want: 0},
+ test_int8{fn: and_127_int8, fnname: "and_127_int8", in: 1, want: 1},
+ test_int8{fn: and_int8_127, fnname: "and_int8_127", in: 1, want: 1},
+ test_int8{fn: and_127_int8, fnname: "and_127_int8", in: 126, want: 126},
+ test_int8{fn: and_int8_127, fnname: "and_int8_127", in: 126, want: 126},
+ test_int8{fn: and_127_int8, fnname: "and_127_int8", in: 127, want: 127},
+ test_int8{fn: and_int8_127, fnname: "and_int8_127", in: 127, want: 127},
+ test_int8{fn: or_Neg128_int8, fnname: "or_Neg128_int8", in: -128, want: -128},
+ test_int8{fn: or_int8_Neg128, fnname: "or_int8_Neg128", in: -128, want: -128},
+ test_int8{fn: or_Neg128_int8, fnname: "or_Neg128_int8", in: -127, want: -127},
+ test_int8{fn: or_int8_Neg128, fnname: "or_int8_Neg128", in: -127, want: -127},
+ test_int8{fn: or_Neg128_int8, fnname: "or_Neg128_int8", in: -1, want: -1},
+ test_int8{fn: or_int8_Neg128, fnname: "or_int8_Neg128", in: -1, want: -1},
+ test_int8{fn: or_Neg128_int8, fnname: "or_Neg128_int8", in: 0, want: -128},
+ test_int8{fn: or_int8_Neg128, fnname: "or_int8_Neg128", in: 0, want: -128},
+ test_int8{fn: or_Neg128_int8, fnname: "or_Neg128_int8", in: 1, want: -127},
+ test_int8{fn: or_int8_Neg128, fnname: "or_int8_Neg128", in: 1, want: -127},
+ test_int8{fn: or_Neg128_int8, fnname: "or_Neg128_int8", in: 126, want: -2},
+ test_int8{fn: or_int8_Neg128, fnname: "or_int8_Neg128", in: 126, want: -2},
+ test_int8{fn: or_Neg128_int8, fnname: "or_Neg128_int8", in: 127, want: -1},
+ test_int8{fn: or_int8_Neg128, fnname: "or_int8_Neg128", in: 127, want: -1},
+ test_int8{fn: or_Neg127_int8, fnname: "or_Neg127_int8", in: -128, want: -127},
+ test_int8{fn: or_int8_Neg127, fnname: "or_int8_Neg127", in: -128, want: -127},
+ test_int8{fn: or_Neg127_int8, fnname: "or_Neg127_int8", in: -127, want: -127},
+ test_int8{fn: or_int8_Neg127, fnname: "or_int8_Neg127", in: -127, want: -127},
+ test_int8{fn: or_Neg127_int8, fnname: "or_Neg127_int8", in: -1, want: -1},
+ test_int8{fn: or_int8_Neg127, fnname: "or_int8_Neg127", in: -1, want: -1},
+ test_int8{fn: or_Neg127_int8, fnname: "or_Neg127_int8", in: 0, want: -127},
+ test_int8{fn: or_int8_Neg127, fnname: "or_int8_Neg127", in: 0, want: -127},
+ test_int8{fn: or_Neg127_int8, fnname: "or_Neg127_int8", in: 1, want: -127},
+ test_int8{fn: or_int8_Neg127, fnname: "or_int8_Neg127", in: 1, want: -127},
+ test_int8{fn: or_Neg127_int8, fnname: "or_Neg127_int8", in: 126, want: -1},
+ test_int8{fn: or_int8_Neg127, fnname: "or_int8_Neg127", in: 126, want: -1},
+ test_int8{fn: or_Neg127_int8, fnname: "or_Neg127_int8", in: 127, want: -1},
+ test_int8{fn: or_int8_Neg127, fnname: "or_int8_Neg127", in: 127, want: -1},
+ test_int8{fn: or_Neg1_int8, fnname: "or_Neg1_int8", in: -128, want: -1},
+ test_int8{fn: or_int8_Neg1, fnname: "or_int8_Neg1", in: -128, want: -1},
+ test_int8{fn: or_Neg1_int8, fnname: "or_Neg1_int8", in: -127, want: -1},
+ test_int8{fn: or_int8_Neg1, fnname: "or_int8_Neg1", in: -127, want: -1},
+ test_int8{fn: or_Neg1_int8, fnname: "or_Neg1_int8", in: -1, want: -1},
+ test_int8{fn: or_int8_Neg1, fnname: "or_int8_Neg1", in: -1, want: -1},
+ test_int8{fn: or_Neg1_int8, fnname: "or_Neg1_int8", in: 0, want: -1},
+ test_int8{fn: or_int8_Neg1, fnname: "or_int8_Neg1", in: 0, want: -1},
+ test_int8{fn: or_Neg1_int8, fnname: "or_Neg1_int8", in: 1, want: -1},
+ test_int8{fn: or_int8_Neg1, fnname: "or_int8_Neg1", in: 1, want: -1},
+ test_int8{fn: or_Neg1_int8, fnname: "or_Neg1_int8", in: 126, want: -1},
+ test_int8{fn: or_int8_Neg1, fnname: "or_int8_Neg1", in: 126, want: -1},
+ test_int8{fn: or_Neg1_int8, fnname: "or_Neg1_int8", in: 127, want: -1},
+ test_int8{fn: or_int8_Neg1, fnname: "or_int8_Neg1", in: 127, want: -1},
+ test_int8{fn: or_0_int8, fnname: "or_0_int8", in: -128, want: -128},
+ test_int8{fn: or_int8_0, fnname: "or_int8_0", in: -128, want: -128},
+ test_int8{fn: or_0_int8, fnname: "or_0_int8", in: -127, want: -127},
+ test_int8{fn: or_int8_0, fnname: "or_int8_0", in: -127, want: -127},
+ test_int8{fn: or_0_int8, fnname: "or_0_int8", in: -1, want: -1},
+ test_int8{fn: or_int8_0, fnname: "or_int8_0", in: -1, want: -1},
+ test_int8{fn: or_0_int8, fnname: "or_0_int8", in: 0, want: 0},
+ test_int8{fn: or_int8_0, fnname: "or_int8_0", in: 0, want: 0},
+ test_int8{fn: or_0_int8, fnname: "or_0_int8", in: 1, want: 1},
+ test_int8{fn: or_int8_0, fnname: "or_int8_0", in: 1, want: 1},
+ test_int8{fn: or_0_int8, fnname: "or_0_int8", in: 126, want: 126},
+ test_int8{fn: or_int8_0, fnname: "or_int8_0", in: 126, want: 126},
+ test_int8{fn: or_0_int8, fnname: "or_0_int8", in: 127, want: 127},
+ test_int8{fn: or_int8_0, fnname: "or_int8_0", in: 127, want: 127},
+ test_int8{fn: or_1_int8, fnname: "or_1_int8", in: -128, want: -127},
+ test_int8{fn: or_int8_1, fnname: "or_int8_1", in: -128, want: -127},
+ test_int8{fn: or_1_int8, fnname: "or_1_int8", in: -127, want: -127},
+ test_int8{fn: or_int8_1, fnname: "or_int8_1", in: -127, want: -127},
+ test_int8{fn: or_1_int8, fnname: "or_1_int8", in: -1, want: -1},
+ test_int8{fn: or_int8_1, fnname: "or_int8_1", in: -1, want: -1},
+ test_int8{fn: or_1_int8, fnname: "or_1_int8", in: 0, want: 1},
+ test_int8{fn: or_int8_1, fnname: "or_int8_1", in: 0, want: 1},
+ test_int8{fn: or_1_int8, fnname: "or_1_int8", in: 1, want: 1},
+ test_int8{fn: or_int8_1, fnname: "or_int8_1", in: 1, want: 1},
+ test_int8{fn: or_1_int8, fnname: "or_1_int8", in: 126, want: 127},
+ test_int8{fn: or_int8_1, fnname: "or_int8_1", in: 126, want: 127},
+ test_int8{fn: or_1_int8, fnname: "or_1_int8", in: 127, want: 127},
+ test_int8{fn: or_int8_1, fnname: "or_int8_1", in: 127, want: 127},
+ test_int8{fn: or_126_int8, fnname: "or_126_int8", in: -128, want: -2},
+ test_int8{fn: or_int8_126, fnname: "or_int8_126", in: -128, want: -2},
+ test_int8{fn: or_126_int8, fnname: "or_126_int8", in: -127, want: -1},
+ test_int8{fn: or_int8_126, fnname: "or_int8_126", in: -127, want: -1},
+ test_int8{fn: or_126_int8, fnname: "or_126_int8", in: -1, want: -1},
+ test_int8{fn: or_int8_126, fnname: "or_int8_126", in: -1, want: -1},
+ test_int8{fn: or_126_int8, fnname: "or_126_int8", in: 0, want: 126},
+ test_int8{fn: or_int8_126, fnname: "or_int8_126", in: 0, want: 126},
+ test_int8{fn: or_126_int8, fnname: "or_126_int8", in: 1, want: 127},
+ test_int8{fn: or_int8_126, fnname: "or_int8_126", in: 1, want: 127},
+ test_int8{fn: or_126_int8, fnname: "or_126_int8", in: 126, want: 126},
+ test_int8{fn: or_int8_126, fnname: "or_int8_126", in: 126, want: 126},
+ test_int8{fn: or_126_int8, fnname: "or_126_int8", in: 127, want: 127},
+ test_int8{fn: or_int8_126, fnname: "or_int8_126", in: 127, want: 127},
+ test_int8{fn: or_127_int8, fnname: "or_127_int8", in: -128, want: -1},
+ test_int8{fn: or_int8_127, fnname: "or_int8_127", in: -128, want: -1},
+ test_int8{fn: or_127_int8, fnname: "or_127_int8", in: -127, want: -1},
+ test_int8{fn: or_int8_127, fnname: "or_int8_127", in: -127, want: -1},
+ test_int8{fn: or_127_int8, fnname: "or_127_int8", in: -1, want: -1},
+ test_int8{fn: or_int8_127, fnname: "or_int8_127", in: -1, want: -1},
+ test_int8{fn: or_127_int8, fnname: "or_127_int8", in: 0, want: 127},
+ test_int8{fn: or_int8_127, fnname: "or_int8_127", in: 0, want: 127},
+ test_int8{fn: or_127_int8, fnname: "or_127_int8", in: 1, want: 127},
+ test_int8{fn: or_int8_127, fnname: "or_int8_127", in: 1, want: 127},
+ test_int8{fn: or_127_int8, fnname: "or_127_int8", in: 126, want: 127},
+ test_int8{fn: or_int8_127, fnname: "or_int8_127", in: 126, want: 127},
+ test_int8{fn: or_127_int8, fnname: "or_127_int8", in: 127, want: 127},
+ test_int8{fn: or_int8_127, fnname: "or_int8_127", in: 127, want: 127},
+ test_int8{fn: xor_Neg128_int8, fnname: "xor_Neg128_int8", in: -128, want: 0},
+ test_int8{fn: xor_int8_Neg128, fnname: "xor_int8_Neg128", in: -128, want: 0},
+ test_int8{fn: xor_Neg128_int8, fnname: "xor_Neg128_int8", in: -127, want: 1},
+ test_int8{fn: xor_int8_Neg128, fnname: "xor_int8_Neg128", in: -127, want: 1},
+ test_int8{fn: xor_Neg128_int8, fnname: "xor_Neg128_int8", in: -1, want: 127},
+ test_int8{fn: xor_int8_Neg128, fnname: "xor_int8_Neg128", in: -1, want: 127},
+ test_int8{fn: xor_Neg128_int8, fnname: "xor_Neg128_int8", in: 0, want: -128},
+ test_int8{fn: xor_int8_Neg128, fnname: "xor_int8_Neg128", in: 0, want: -128},
+ test_int8{fn: xor_Neg128_int8, fnname: "xor_Neg128_int8", in: 1, want: -127},
+ test_int8{fn: xor_int8_Neg128, fnname: "xor_int8_Neg128", in: 1, want: -127},
+ test_int8{fn: xor_Neg128_int8, fnname: "xor_Neg128_int8", in: 126, want: -2},
+ test_int8{fn: xor_int8_Neg128, fnname: "xor_int8_Neg128", in: 126, want: -2},
+ test_int8{fn: xor_Neg128_int8, fnname: "xor_Neg128_int8", in: 127, want: -1},
+ test_int8{fn: xor_int8_Neg128, fnname: "xor_int8_Neg128", in: 127, want: -1},
+ test_int8{fn: xor_Neg127_int8, fnname: "xor_Neg127_int8", in: -128, want: 1},
+ test_int8{fn: xor_int8_Neg127, fnname: "xor_int8_Neg127", in: -128, want: 1},
+ test_int8{fn: xor_Neg127_int8, fnname: "xor_Neg127_int8", in: -127, want: 0},
+ test_int8{fn: xor_int8_Neg127, fnname: "xor_int8_Neg127", in: -127, want: 0},
+ test_int8{fn: xor_Neg127_int8, fnname: "xor_Neg127_int8", in: -1, want: 126},
+ test_int8{fn: xor_int8_Neg127, fnname: "xor_int8_Neg127", in: -1, want: 126},
+ test_int8{fn: xor_Neg127_int8, fnname: "xor_Neg127_int8", in: 0, want: -127},
+ test_int8{fn: xor_int8_Neg127, fnname: "xor_int8_Neg127", in: 0, want: -127},
+ test_int8{fn: xor_Neg127_int8, fnname: "xor_Neg127_int8", in: 1, want: -128},
+ test_int8{fn: xor_int8_Neg127, fnname: "xor_int8_Neg127", in: 1, want: -128},
+ test_int8{fn: xor_Neg127_int8, fnname: "xor_Neg127_int8", in: 126, want: -1},
+ test_int8{fn: xor_int8_Neg127, fnname: "xor_int8_Neg127", in: 126, want: -1},
+ test_int8{fn: xor_Neg127_int8, fnname: "xor_Neg127_int8", in: 127, want: -2},
+ test_int8{fn: xor_int8_Neg127, fnname: "xor_int8_Neg127", in: 127, want: -2},
+ test_int8{fn: xor_Neg1_int8, fnname: "xor_Neg1_int8", in: -128, want: 127},
+ test_int8{fn: xor_int8_Neg1, fnname: "xor_int8_Neg1", in: -128, want: 127},
+ test_int8{fn: xor_Neg1_int8, fnname: "xor_Neg1_int8", in: -127, want: 126},
+ test_int8{fn: xor_int8_Neg1, fnname: "xor_int8_Neg1", in: -127, want: 126},
+ test_int8{fn: xor_Neg1_int8, fnname: "xor_Neg1_int8", in: -1, want: 0},
+ test_int8{fn: xor_int8_Neg1, fnname: "xor_int8_Neg1", in: -1, want: 0},
+ test_int8{fn: xor_Neg1_int8, fnname: "xor_Neg1_int8", in: 0, want: -1},
+ test_int8{fn: xor_int8_Neg1, fnname: "xor_int8_Neg1", in: 0, want: -1},
+ test_int8{fn: xor_Neg1_int8, fnname: "xor_Neg1_int8", in: 1, want: -2},
+ test_int8{fn: xor_int8_Neg1, fnname: "xor_int8_Neg1", in: 1, want: -2},
+ test_int8{fn: xor_Neg1_int8, fnname: "xor_Neg1_int8", in: 126, want: -127},
+ test_int8{fn: xor_int8_Neg1, fnname: "xor_int8_Neg1", in: 126, want: -127},
+ test_int8{fn: xor_Neg1_int8, fnname: "xor_Neg1_int8", in: 127, want: -128},
+ test_int8{fn: xor_int8_Neg1, fnname: "xor_int8_Neg1", in: 127, want: -128},
+ test_int8{fn: xor_0_int8, fnname: "xor_0_int8", in: -128, want: -128},
+ test_int8{fn: xor_int8_0, fnname: "xor_int8_0", in: -128, want: -128},
+ test_int8{fn: xor_0_int8, fnname: "xor_0_int8", in: -127, want: -127},
+ test_int8{fn: xor_int8_0, fnname: "xor_int8_0", in: -127, want: -127},
+ test_int8{fn: xor_0_int8, fnname: "xor_0_int8", in: -1, want: -1},
+ test_int8{fn: xor_int8_0, fnname: "xor_int8_0", in: -1, want: -1},
+ test_int8{fn: xor_0_int8, fnname: "xor_0_int8", in: 0, want: 0},
+ test_int8{fn: xor_int8_0, fnname: "xor_int8_0", in: 0, want: 0},
+ test_int8{fn: xor_0_int8, fnname: "xor_0_int8", in: 1, want: 1},
+ test_int8{fn: xor_int8_0, fnname: "xor_int8_0", in: 1, want: 1},
+ test_int8{fn: xor_0_int8, fnname: "xor_0_int8", in: 126, want: 126},
+ test_int8{fn: xor_int8_0, fnname: "xor_int8_0", in: 126, want: 126},
+ test_int8{fn: xor_0_int8, fnname: "xor_0_int8", in: 127, want: 127},
+ test_int8{fn: xor_int8_0, fnname: "xor_int8_0", in: 127, want: 127},
+ test_int8{fn: xor_1_int8, fnname: "xor_1_int8", in: -128, want: -127},
+ test_int8{fn: xor_int8_1, fnname: "xor_int8_1", in: -128, want: -127},
+ test_int8{fn: xor_1_int8, fnname: "xor_1_int8", in: -127, want: -128},
+ test_int8{fn: xor_int8_1, fnname: "xor_int8_1", in: -127, want: -128},
+ test_int8{fn: xor_1_int8, fnname: "xor_1_int8", in: -1, want: -2},
+ test_int8{fn: xor_int8_1, fnname: "xor_int8_1", in: -1, want: -2},
+ test_int8{fn: xor_1_int8, fnname: "xor_1_int8", in: 0, want: 1},
+ test_int8{fn: xor_int8_1, fnname: "xor_int8_1", in: 0, want: 1},
+ test_int8{fn: xor_1_int8, fnname: "xor_1_int8", in: 1, want: 0},
+ test_int8{fn: xor_int8_1, fnname: "xor_int8_1", in: 1, want: 0},
+ test_int8{fn: xor_1_int8, fnname: "xor_1_int8", in: 126, want: 127},
+ test_int8{fn: xor_int8_1, fnname: "xor_int8_1", in: 126, want: 127},
+ test_int8{fn: xor_1_int8, fnname: "xor_1_int8", in: 127, want: 126},
+ test_int8{fn: xor_int8_1, fnname: "xor_int8_1", in: 127, want: 126},
+ test_int8{fn: xor_126_int8, fnname: "xor_126_int8", in: -128, want: -2},
+ test_int8{fn: xor_int8_126, fnname: "xor_int8_126", in: -128, want: -2},
+ test_int8{fn: xor_126_int8, fnname: "xor_126_int8", in: -127, want: -1},
+ test_int8{fn: xor_int8_126, fnname: "xor_int8_126", in: -127, want: -1},
+ test_int8{fn: xor_126_int8, fnname: "xor_126_int8", in: -1, want: -127},
+ test_int8{fn: xor_int8_126, fnname: "xor_int8_126", in: -1, want: -127},
+ test_int8{fn: xor_126_int8, fnname: "xor_126_int8", in: 0, want: 126},
+ test_int8{fn: xor_int8_126, fnname: "xor_int8_126", in: 0, want: 126},
+ test_int8{fn: xor_126_int8, fnname: "xor_126_int8", in: 1, want: 127},
+ test_int8{fn: xor_int8_126, fnname: "xor_int8_126", in: 1, want: 127},
+ test_int8{fn: xor_126_int8, fnname: "xor_126_int8", in: 126, want: 0},
+ test_int8{fn: xor_int8_126, fnname: "xor_int8_126", in: 126, want: 0},
+ test_int8{fn: xor_126_int8, fnname: "xor_126_int8", in: 127, want: 1},
+ test_int8{fn: xor_int8_126, fnname: "xor_int8_126", in: 127, want: 1},
+ test_int8{fn: xor_127_int8, fnname: "xor_127_int8", in: -128, want: -1},
+ test_int8{fn: xor_int8_127, fnname: "xor_int8_127", in: -128, want: -1},
+ test_int8{fn: xor_127_int8, fnname: "xor_127_int8", in: -127, want: -2},
+ test_int8{fn: xor_int8_127, fnname: "xor_int8_127", in: -127, want: -2},
+ test_int8{fn: xor_127_int8, fnname: "xor_127_int8", in: -1, want: -128},
+ test_int8{fn: xor_int8_127, fnname: "xor_int8_127", in: -1, want: -128},
+ test_int8{fn: xor_127_int8, fnname: "xor_127_int8", in: 0, want: 127},
+ test_int8{fn: xor_int8_127, fnname: "xor_int8_127", in: 0, want: 127},
+ test_int8{fn: xor_127_int8, fnname: "xor_127_int8", in: 1, want: 126},
+ test_int8{fn: xor_int8_127, fnname: "xor_int8_127", in: 1, want: 126},
+ test_int8{fn: xor_127_int8, fnname: "xor_127_int8", in: 126, want: 1},
+ test_int8{fn: xor_int8_127, fnname: "xor_int8_127", in: 126, want: 1},
+ test_int8{fn: xor_127_int8, fnname: "xor_127_int8", in: 127, want: 0},
+ test_int8{fn: xor_int8_127, fnname: "xor_int8_127", in: 127, want: 0}}
+
+// TestArithmeticConst tests results for arithmetic operations against constants.
+func TestArithmeticConst(t *testing.T) {
+ for _, test := range tests_uint64 {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_uint64mul {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_int64 {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_int64mul {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_uint32 {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_uint32mul {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_int32 {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_int32mul {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_uint16 {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_int16 {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_uint8 {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+ for _, test := range tests_int8 {
+ if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+
+}
diff --git a/src/cmd/compile/internal/gc/testdata/arith_test.go b/src/cmd/compile/internal/gc/testdata/arith_test.go
new file mode 100644
index 0000000..158fedc
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/arith_test.go
@@ -0,0 +1,1454 @@
+// Copyright 2015 The Go 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 (
+ "math"
+ "runtime"
+ "testing"
+)
+
+const (
+ y = 0x0fffFFFF
+)
+
+var (
+ g8 int8
+ g16 int16
+ g32 int32
+ g64 int64
+)
+
+//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(t *testing.T) {
+ allSet := ^uint64(0)
+ if want, got := uint64(0x7ffffffffffffff), rshNop1(allSet); want != got {
+ t.Errorf("testShiftRemoval rshNop1 failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint64(0x3ffffffffffffff), rshNop2(allSet); want != got {
+ t.Errorf("testShiftRemoval rshNop2 failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint64(0x7fffffffffffff), rshNop3(allSet); want != got {
+ t.Errorf("testShiftRemoval rshNop3 failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint64(0xffffffffffffffe), rshNotNop(allSet); want != got {
+ t.Errorf("testShiftRemoval rshNotNop failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint64(0xffffffffffffffe0), lshNop1(allSet); want != got {
+ t.Errorf("testShiftRemoval lshNop1 failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint64(0xffffffffffffffc0), lshNop2(allSet); want != got {
+ t.Errorf("testShiftRemoval lshNop2 failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint64(0xfffffffffffffe00), lshNop3(allSet); want != got {
+ t.Errorf("testShiftRemoval lshNop3 failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint64(0x7ffffffffffffff0), lshNotNop(allSet); want != got {
+ t.Errorf("testShiftRemoval lshNotNop failed, wanted %d got %d", want, got)
+ }
+}
+
+//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(t *testing.T) {
+ testData := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}
+ if want, got := uint64(0x0908070605040302), parseLE64(testData); want != got {
+ t.Errorf("testLoadCombine failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint32(0x05040302), parseLE32(testData); want != got {
+ t.Errorf("testLoadCombine failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint16(0x0302), parseLE16(testData); want != got {
+ t.Errorf("testLoadCombine failed, wanted %d got %d", want, got)
+ }
+}
+
+var loadSymData = [...]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
+
+func testLoadSymCombine(t *testing.T) {
+ w2 := uint16(0x0201)
+ g2 := uint16(loadSymData[0]) | uint16(loadSymData[1])<<8
+ if g2 != w2 {
+ t.Errorf("testLoadSymCombine failed, wanted %d got %d", w2, g2)
+ }
+ w4 := uint32(0x04030201)
+ g4 := uint32(loadSymData[0]) | uint32(loadSymData[1])<<8 |
+ uint32(loadSymData[2])<<16 | uint32(loadSymData[3])<<24
+ if g4 != w4 {
+ t.Errorf("testLoadSymCombine failed, wanted %d got %d", w4, g4)
+ }
+ 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 {
+ t.Errorf("testLoadSymCombine failed, wanted %d got %d", w8, g8)
+ }
+}
+
+//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(t *testing.T) {
+ if want, got := uint32(268435440), invalidAdd_ssa(1); want != got {
+ t.Errorf("testLargeConst add failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint32(4026531858), invalidSub_ssa(1); want != got {
+ t.Errorf("testLargeConst sub failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint32(268435455), invalidMul_ssa(1); want != got {
+ t.Errorf("testLargeConst mul failed, wanted %d got %d", want, got)
+ }
+}
+
+// testArithRshConst ensures that "const >> const" right shifts correctly perform
+// sign extension on the lhs constant
+func testArithRshConst(t *testing.T) {
+ wantu := uint64(0x4000000000000000)
+ if got := arithRshuConst_ssa(); got != wantu {
+ t.Errorf("arithRshuConst failed, wanted %d got %d", wantu, got)
+ }
+
+ wants := int64(-0x4000000000000000)
+ if got := arithRshConst_ssa(); got != wants {
+ t.Errorf("arithRshConst failed, wanted %d got %d", wants, got)
+ }
+}
+
+//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(t *testing.T) {
+ want := int64(-1)
+ if got := arithConstShift_ssa(-1); want != got {
+ t.Errorf("arithConstShift_ssa(-1) failed, wanted %d got %d", want, got)
+ }
+ want = 0
+ if got := arithConstShift_ssa(1); want != got {
+ t.Errorf("arithConstShift_ssa(1) failed, wanted %d got %d", want, got)
+ }
+}
+
+// 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(t *testing.T) {
+ want := int64(0)
+ for x := int64(-127); x < int64(127); x++ {
+ got := overflowConstShift64_ssa(x)
+ if want != got {
+ t.Errorf("overflowShift64 failed, wanted %d got %d", want, got)
+ }
+ got = int64(overflowConstShift32_ssa(x))
+ if want != got {
+ t.Errorf("overflowShift32 failed, wanted %d got %d", want, got)
+ }
+ got = int64(overflowConstShift16_ssa(x))
+ if want != got {
+ t.Errorf("overflowShift16 failed, wanted %d got %d", want, got)
+ }
+ got = int64(overflowConstShift8_ssa(x))
+ if want != got {
+ t.Errorf("overflowShift8 failed, wanted %d got %d", want, got)
+ }
+ }
+}
+
+// test64BitConstMult tests that rewrite rules don't fold 64 bit constants
+// into multiply instructions.
+func test64BitConstMult(t *testing.T) {
+ want := int64(103079215109)
+ if got := test64BitConstMult_ssa(1, 2); want != got {
+ t.Errorf("test64BitConstMult failed, wanted %d got %d", want, got)
+ }
+}
+
+//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(t *testing.T) {
+ want := int64(3567671782835376650)
+ if got := test64BitConstAdd_ssa(1, 2); want != got {
+ t.Errorf("test64BitConstAdd failed, wanted %d got %d", want, got)
+ }
+}
+
+//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(t *testing.T) {
+ want := int8(-9)
+ if got := testRegallocCVSpill_ssa(1, 2, 3, 4); want != got {
+ t.Errorf("testRegallocCVSpill failed, wanted %d got %d", want, got)
+ }
+}
+
+//go:noinline
+func testRegallocCVSpill_ssa(a, b, c, d int8) int8 {
+ return a + -32 + b + 63*c*-87*d
+}
+
+func testBitwiseLogic(t *testing.T) {
+ a, b := uint32(57623283), uint32(1314713839)
+ if want, got := uint32(38551779), testBitwiseAnd_ssa(a, b); want != got {
+ t.Errorf("testBitwiseAnd failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint32(1333785343), testBitwiseOr_ssa(a, b); want != got {
+ t.Errorf("testBitwiseOr failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint32(1295233564), testBitwiseXor_ssa(a, b); want != got {
+ t.Errorf("testBitwiseXor failed, wanted %d got %d", want, got)
+ }
+ if want, got := int32(832), testBitwiseLsh_ssa(13, 4, 2); want != got {
+ t.Errorf("testBitwiseLsh failed, wanted %d got %d", want, got)
+ }
+ if want, got := int32(0), testBitwiseLsh_ssa(13, 25, 15); want != got {
+ t.Errorf("testBitwiseLsh failed, wanted %d got %d", want, got)
+ }
+ if want, got := int32(0), testBitwiseLsh_ssa(-13, 25, 15); want != got {
+ t.Errorf("testBitwiseLsh failed, wanted %d got %d", want, got)
+ }
+ if want, got := int32(-13), testBitwiseRsh_ssa(-832, 4, 2); want != got {
+ t.Errorf("testBitwiseRsh failed, wanted %d got %d", want, got)
+ }
+ if want, got := int32(0), testBitwiseRsh_ssa(13, 25, 15); want != got {
+ t.Errorf("testBitwiseRsh failed, wanted %d got %d", want, got)
+ }
+ if want, got := int32(-1), testBitwiseRsh_ssa(-13, 25, 15); want != got {
+ t.Errorf("testBitwiseRsh failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint32(0x3ffffff), testBitwiseRshU_ssa(0xffffffff, 4, 2); want != got {
+ t.Errorf("testBitwiseRshU failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint32(0), testBitwiseRshU_ssa(13, 25, 15); want != got {
+ t.Errorf("testBitwiseRshU failed, wanted %d got %d", want, got)
+ }
+ if want, got := uint32(0), testBitwiseRshU_ssa(0x8aaaaaaa, 25, 15); want != got {
+ t.Errorf("testBitwiseRshU failed, wanted %d got %d", want, got)
+ }
+}
+
+//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(t *testing.T) {
+ want := 141
+ if got := testShiftCX_ssa(); want != got {
+ t.Errorf("testShiftCX failed, wanted %d got %d", want, got)
+ }
+}
+
+// testSubqToNegq ensures that the SUBQ -> NEGQ translation works correctly.
+func testSubqToNegq(t *testing.T) {
+ want := int64(-318294940372190156)
+ if got := testSubqToNegq_ssa(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2); want != got {
+ t.Errorf("testSubqToNegq failed, wanted %d got %d", want, got)
+ }
+}
+
+//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(t *testing.T) {
+ want1, want2 := int32(0x55555555), int32(-0x55555556)
+ if got1, got2 := testOcom_ssa(0x55555555, 0x55555555); want1 != got1 || want2 != got2 {
+ t.Errorf("testOcom failed, wanted %d and %d got %d and %d", want1, want2, got1, got2)
+ }
+}
+
+//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(t *testing.T) {
+ 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 {
+ t.Errorf("lrot1_ssa(0xf, 0xf, 0xf, 0xf)=%d %d %d %d, got %d %d %d %d", wantA, wantB, wantC, wantD, a, b, c, d)
+ }
+ x := lrot2_ssa(0xb0000001, 32)
+ wantX := uint32(0xb0000001)
+ if x != wantX {
+ t.Errorf("lrot2_ssa(0xb0000001, 32)=%d, got %d", wantX, x)
+ }
+ x = lrot3_ssa(0xb0000001)
+ if x != wantX {
+ t.Errorf("lrot3_ssa(0xb0000001)=%d, got %d", wantX, x)
+ }
+
+}
+
+//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(t *testing.T) {
+ x1 := sub1_ssa()
+ want1 := uint64(6)
+ if x1 != want1 {
+ t.Errorf("sub1_ssa()=%d, got %d", want1, x1)
+ }
+ x2 := sub2_ssa()
+ want2 := uint8(251)
+ if x2 != want2 {
+ t.Errorf("sub2_ssa()=%d, got %d", want2, x2)
+ }
+}
+
+//go:noinline
+func orPhi_ssa(a bool, x int) int {
+ v := 0
+ if a {
+ v = -1
+ } else {
+ v = -1
+ }
+ return x | v
+}
+
+func testOrPhi(t *testing.T) {
+ if want, got := -1, orPhi_ssa(true, 4); got != want {
+ t.Errorf("orPhi_ssa(true, 4)=%d, want %d", got, want)
+ }
+ if want, got := -1, orPhi_ssa(false, 0); got != want {
+ t.Errorf("orPhi_ssa(false, 0)=%d, want %d", got, 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(t *testing.T) {
+ a, b := uint32(10), uint32(42)
+ if want, got := a+b<<3, addshiftLL_ssa(a, b); got != want {
+ t.Errorf("addshiftLL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a-b<<3, subshiftLL_ssa(a, b); got != want {
+ t.Errorf("subshiftLL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a<<3-b, rsbshiftLL_ssa(a, b); got != want {
+ t.Errorf("rsbshiftLL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a&(b<<3), andshiftLL_ssa(a, b); got != want {
+ t.Errorf("andshiftLL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a|b<<3, orshiftLL_ssa(a, b); got != want {
+ t.Errorf("orshiftLL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a^b<<3, xorshiftLL_ssa(a, b); got != want {
+ t.Errorf("xorshiftLL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a&^(b<<3), bicshiftLL_ssa(a, b); got != want {
+ t.Errorf("bicshiftLL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := ^(a << 3), notshiftLL_ssa(a); got != want {
+ t.Errorf("notshiftLL_ssa(10) = %d want %d", got, want)
+ }
+ if want, got := a+b>>3, addshiftRL_ssa(a, b); got != want {
+ t.Errorf("addshiftRL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a-b>>3, subshiftRL_ssa(a, b); got != want {
+ t.Errorf("subshiftRL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a>>3-b, rsbshiftRL_ssa(a, b); got != want {
+ t.Errorf("rsbshiftRL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a&(b>>3), andshiftRL_ssa(a, b); got != want {
+ t.Errorf("andshiftRL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a|b>>3, orshiftRL_ssa(a, b); got != want {
+ t.Errorf("orshiftRL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a^b>>3, xorshiftRL_ssa(a, b); got != want {
+ t.Errorf("xorshiftRL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := a&^(b>>3), bicshiftRL_ssa(a, b); got != want {
+ t.Errorf("bicshiftRL_ssa(10, 42) = %d want %d", got, want)
+ }
+ if want, got := ^(a >> 3), notshiftRL_ssa(a); got != want {
+ t.Errorf("notshiftRL_ssa(10) = %d want %d", got, want)
+ }
+ c, d := int32(10), int32(-42)
+ if want, got := c+d>>3, addshiftRA_ssa(c, d); got != want {
+ t.Errorf("addshiftRA_ssa(10, -42) = %d want %d", got, want)
+ }
+ if want, got := c-d>>3, subshiftRA_ssa(c, d); got != want {
+ t.Errorf("subshiftRA_ssa(10, -42) = %d want %d", got, want)
+ }
+ if want, got := c>>3-d, rsbshiftRA_ssa(c, d); got != want {
+ t.Errorf("rsbshiftRA_ssa(10, -42) = %d want %d", got, want)
+ }
+ if want, got := c&(d>>3), andshiftRA_ssa(c, d); got != want {
+ t.Errorf("andshiftRA_ssa(10, -42) = %d want %d", got, want)
+ }
+ if want, got := c|d>>3, orshiftRA_ssa(c, d); got != want {
+ t.Errorf("orshiftRA_ssa(10, -42) = %d want %d", got, want)
+ }
+ if want, got := c^d>>3, xorshiftRA_ssa(c, d); got != want {
+ t.Errorf("xorshiftRA_ssa(10, -42) = %d want %d", got, want)
+ }
+ if want, got := c&^(d>>3), bicshiftRA_ssa(c, d); got != want {
+ t.Errorf("bicshiftRA_ssa(10, -42) = %d want %d", got, want)
+ }
+ if want, got := ^(d >> 3), notshiftRA_ssa(d); got != want {
+ t.Errorf("notshiftRA_ssa(-42) = %d want %d", got, want)
+ }
+ s := uint8(3)
+ if want, got := a+b<<s, addshiftLLreg_ssa(a, b, s); got != want {
+ t.Errorf("addshiftLLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a-b<<s, subshiftLLreg_ssa(a, b, s); got != want {
+ t.Errorf("subshiftLLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a<<s-b, rsbshiftLLreg_ssa(a, b, s); got != want {
+ t.Errorf("rsbshiftLLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a&(b<<s), andshiftLLreg_ssa(a, b, s); got != want {
+ t.Errorf("andshiftLLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a|b<<s, orshiftLLreg_ssa(a, b, s); got != want {
+ t.Errorf("orshiftLLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a^b<<s, xorshiftLLreg_ssa(a, b, s); got != want {
+ t.Errorf("xorshiftLLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a&^(b<<s), bicshiftLLreg_ssa(a, b, s); got != want {
+ t.Errorf("bicshiftLLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := ^(a << s), notshiftLLreg_ssa(a, s); got != want {
+ t.Errorf("notshiftLLreg_ssa(10) = %d want %d", got, want)
+ }
+ if want, got := a+b>>s, addshiftRLreg_ssa(a, b, s); got != want {
+ t.Errorf("addshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a-b>>s, subshiftRLreg_ssa(a, b, s); got != want {
+ t.Errorf("subshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a>>s-b, rsbshiftRLreg_ssa(a, b, s); got != want {
+ t.Errorf("rsbshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a&(b>>s), andshiftRLreg_ssa(a, b, s); got != want {
+ t.Errorf("andshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a|b>>s, orshiftRLreg_ssa(a, b, s); got != want {
+ t.Errorf("orshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a^b>>s, xorshiftRLreg_ssa(a, b, s); got != want {
+ t.Errorf("xorshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := a&^(b>>s), bicshiftRLreg_ssa(a, b, s); got != want {
+ t.Errorf("bicshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want)
+ }
+ if want, got := ^(a >> s), notshiftRLreg_ssa(a, s); got != want {
+ t.Errorf("notshiftRLreg_ssa(10) = %d want %d", got, want)
+ }
+ if want, got := c+d>>s, addshiftRAreg_ssa(c, d, s); got != want {
+ t.Errorf("addshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want)
+ }
+ if want, got := c-d>>s, subshiftRAreg_ssa(c, d, s); got != want {
+ t.Errorf("subshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want)
+ }
+ if want, got := c>>s-d, rsbshiftRAreg_ssa(c, d, s); got != want {
+ t.Errorf("rsbshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want)
+ }
+ if want, got := c&(d>>s), andshiftRAreg_ssa(c, d, s); got != want {
+ t.Errorf("andshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want)
+ }
+ if want, got := c|d>>s, orshiftRAreg_ssa(c, d, s); got != want {
+ t.Errorf("orshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want)
+ }
+ if want, got := c^d>>s, xorshiftRAreg_ssa(c, d, s); got != want {
+ t.Errorf("xorshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want)
+ }
+ if want, got := c&^(d>>s), bicshiftRAreg_ssa(c, d, s); got != want {
+ t.Errorf("bicshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want)
+ }
+ if want, got := ^(d >> s), notshiftRAreg_ssa(d, s); got != want {
+ t.Errorf("notshiftRAreg_ssa(-42, 3) = %d want %d", got, want)
+ }
+}
+
+// TestArithmetic tests that both backends have the same result for arithmetic expressions.
+func TestArithmetic(t *testing.T) {
+ test64BitConstMult(t)
+ test64BitConstAdd(t)
+ testRegallocCVSpill(t)
+ testSubqToNegq(t)
+ testBitwiseLogic(t)
+ testOcom(t)
+ testLrot(t)
+ testShiftCX(t)
+ testSubConst(t)
+ testOverflowConstShift(t)
+ testArithConstShift(t)
+ testArithRshConst(t)
+ testLargeConst(t)
+ testLoadCombine(t)
+ testLoadSymCombine(t)
+ testShiftRemoval(t)
+ testShiftedOps(t)
+ testDivFixUp(t)
+ testDivisibleSignedPow2(t)
+ testDivisibility(t)
+}
+
+// testDivFixUp ensures that signed division fix-ups are being generated.
+func testDivFixUp(t *testing.T) {
+ defer func() {
+ if r := recover(); r != nil {
+ t.Error("testDivFixUp failed")
+ if e, ok := r.(runtime.Error); ok {
+ t.Logf("%v\n", e.Error())
+ }
+ }
+ }()
+ var w int8 = -128
+ var x int16 = -32768
+ var y int32 = -2147483648
+ var z int64 = -9223372036854775808
+
+ for i := -5; i < 0; i++ {
+ g8 = w / int8(i)
+ g16 = x / int16(i)
+ g32 = y / int32(i)
+ g64 = z / int64(i)
+ g8 = w % int8(i)
+ g16 = x % int16(i)
+ g32 = y % int32(i)
+ g64 = z % int64(i)
+ }
+}
+
+//go:noinline
+func divisible_int8_2to1(x int8) bool {
+ return x%(1<<1) == 0
+}
+
+//go:noinline
+func divisible_int8_2to2(x int8) bool {
+ return x%(1<<2) == 0
+}
+
+//go:noinline
+func divisible_int8_2to3(x int8) bool {
+ return x%(1<<3) == 0
+}
+
+//go:noinline
+func divisible_int8_2to4(x int8) bool {
+ return x%(1<<4) == 0
+}
+
+//go:noinline
+func divisible_int8_2to5(x int8) bool {
+ return x%(1<<5) == 0
+}
+
+//go:noinline
+func divisible_int8_2to6(x int8) bool {
+ return x%(1<<6) == 0
+}
+
+//go:noinline
+func divisible_int16_2to1(x int16) bool {
+ return x%(1<<1) == 0
+}
+
+//go:noinline
+func divisible_int16_2to2(x int16) bool {
+ return x%(1<<2) == 0
+}
+
+//go:noinline
+func divisible_int16_2to3(x int16) bool {
+ return x%(1<<3) == 0
+}
+
+//go:noinline
+func divisible_int16_2to4(x int16) bool {
+ return x%(1<<4) == 0
+}
+
+//go:noinline
+func divisible_int16_2to5(x int16) bool {
+ return x%(1<<5) == 0
+}
+
+//go:noinline
+func divisible_int16_2to6(x int16) bool {
+ return x%(1<<6) == 0
+}
+
+//go:noinline
+func divisible_int16_2to7(x int16) bool {
+ return x%(1<<7) == 0
+}
+
+//go:noinline
+func divisible_int16_2to8(x int16) bool {
+ return x%(1<<8) == 0
+}
+
+//go:noinline
+func divisible_int16_2to9(x int16) bool {
+ return x%(1<<9) == 0
+}
+
+//go:noinline
+func divisible_int16_2to10(x int16) bool {
+ return x%(1<<10) == 0
+}
+
+//go:noinline
+func divisible_int16_2to11(x int16) bool {
+ return x%(1<<11) == 0
+}
+
+//go:noinline
+func divisible_int16_2to12(x int16) bool {
+ return x%(1<<12) == 0
+}
+
+//go:noinline
+func divisible_int16_2to13(x int16) bool {
+ return x%(1<<13) == 0
+}
+
+//go:noinline
+func divisible_int16_2to14(x int16) bool {
+ return x%(1<<14) == 0
+}
+
+//go:noinline
+func divisible_int32_2to4(x int32) bool {
+ return x%(1<<4) == 0
+}
+
+//go:noinline
+func divisible_int32_2to15(x int32) bool {
+ return x%(1<<15) == 0
+}
+
+//go:noinline
+func divisible_int32_2to26(x int32) bool {
+ return x%(1<<26) == 0
+}
+
+//go:noinline
+func divisible_int64_2to4(x int64) bool {
+ return x%(1<<4) == 0
+}
+
+//go:noinline
+func divisible_int64_2to15(x int64) bool {
+ return x%(1<<15) == 0
+}
+
+//go:noinline
+func divisible_int64_2to26(x int64) bool {
+ return x%(1<<26) == 0
+}
+
+//go:noinline
+func divisible_int64_2to34(x int64) bool {
+ return x%(1<<34) == 0
+}
+
+//go:noinline
+func divisible_int64_2to48(x int64) bool {
+ return x%(1<<48) == 0
+}
+
+//go:noinline
+func divisible_int64_2to57(x int64) bool {
+ return x%(1<<57) == 0
+}
+
+// testDivisibleSignedPow2 confirms that x%(1<<k)==0 is rewritten correctly
+func testDivisibleSignedPow2(t *testing.T) {
+ var i int64
+ var pow2 = []int64{
+ 1,
+ 1 << 1,
+ 1 << 2,
+ 1 << 3,
+ 1 << 4,
+ 1 << 5,
+ 1 << 6,
+ 1 << 7,
+ 1 << 8,
+ 1 << 9,
+ 1 << 10,
+ 1 << 11,
+ 1 << 12,
+ 1 << 13,
+ 1 << 14,
+ }
+ // exhaustive test for int8
+ for i = math.MinInt8; i <= math.MaxInt8; i++ {
+ if want, got := int8(i)%int8(pow2[1]) == 0, divisible_int8_2to1(int8(i)); got != want {
+ t.Errorf("divisible_int8_2to1(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int8(i)%int8(pow2[2]) == 0, divisible_int8_2to2(int8(i)); got != want {
+ t.Errorf("divisible_int8_2to2(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int8(i)%int8(pow2[3]) == 0, divisible_int8_2to3(int8(i)); got != want {
+ t.Errorf("divisible_int8_2to3(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int8(i)%int8(pow2[4]) == 0, divisible_int8_2to4(int8(i)); got != want {
+ t.Errorf("divisible_int8_2to4(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int8(i)%int8(pow2[5]) == 0, divisible_int8_2to5(int8(i)); got != want {
+ t.Errorf("divisible_int8_2to5(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int8(i)%int8(pow2[6]) == 0, divisible_int8_2to6(int8(i)); got != want {
+ t.Errorf("divisible_int8_2to6(%d) = %v want %v", i, got, want)
+ }
+ }
+ // exhaustive test for int16
+ for i = math.MinInt16; i <= math.MaxInt16; i++ {
+ if want, got := int16(i)%int16(pow2[1]) == 0, divisible_int16_2to1(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to1(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[2]) == 0, divisible_int16_2to2(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to2(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[3]) == 0, divisible_int16_2to3(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to3(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[4]) == 0, divisible_int16_2to4(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to4(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[5]) == 0, divisible_int16_2to5(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to5(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[6]) == 0, divisible_int16_2to6(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to6(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[7]) == 0, divisible_int16_2to7(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to7(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[8]) == 0, divisible_int16_2to8(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to8(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[9]) == 0, divisible_int16_2to9(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to9(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[10]) == 0, divisible_int16_2to10(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to10(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[11]) == 0, divisible_int16_2to11(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to11(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[12]) == 0, divisible_int16_2to12(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to12(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[13]) == 0, divisible_int16_2to13(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to13(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(pow2[14]) == 0, divisible_int16_2to14(int16(i)); got != want {
+ t.Errorf("divisible_int16_2to14(%d) = %v want %v", i, got, want)
+ }
+ }
+ // spot check for int32 and int64
+ var (
+ two4 int64 = 1 << 4
+ two15 int64 = 1 << 15
+ two26 int64 = 1 << 26
+ two34 int64 = 1 << 34
+ two48 int64 = 1 << 48
+ two57 int64 = 1 << 57
+ )
+ var xs = []int64{two4, two4 + 3, -3 * two4, -3*two4 + 1,
+ two15, two15 + 3, -3 * two15, -3*two15 + 1,
+ two26, two26 + 37, -5 * two26, -5*two26 + 2,
+ two34, two34 + 356, -7 * two34, -7*two34 + 13,
+ two48, two48 + 3000, -12 * two48, -12*two48 + 1111,
+ two57, two57 + 397654, -15 * two57, -15*two57 + 11234,
+ }
+ for _, x := range xs {
+ if int64(int32(x)) == x {
+ if want, got := int32(x)%int32(two4) == 0, divisible_int32_2to4(int32(x)); got != want {
+ t.Errorf("divisible_int32_2to4(%d) = %v want %v", x, got, want)
+ }
+
+ if want, got := int32(x)%int32(two15) == 0, divisible_int32_2to15(int32(x)); got != want {
+ t.Errorf("divisible_int32_2to15(%d) = %v want %v", x, got, want)
+ }
+
+ if want, got := int32(x)%int32(two26) == 0, divisible_int32_2to26(int32(x)); got != want {
+ t.Errorf("divisible_int32_2to26(%d) = %v want %v", x, got, want)
+ }
+ }
+ // spot check for int64
+ if want, got := x%two4 == 0, divisible_int64_2to4(x); got != want {
+ t.Errorf("divisible_int64_2to4(%d) = %v want %v", x, got, want)
+ }
+
+ if want, got := x%two15 == 0, divisible_int64_2to15(x); got != want {
+ t.Errorf("divisible_int64_2to15(%d) = %v want %v", x, got, want)
+ }
+
+ if want, got := x%two26 == 0, divisible_int64_2to26(x); got != want {
+ t.Errorf("divisible_int64_2to26(%d) = %v want %v", x, got, want)
+ }
+
+ if want, got := x%two34 == 0, divisible_int64_2to34(x); got != want {
+ t.Errorf("divisible_int64_2to34(%d) = %v want %v", x, got, want)
+ }
+
+ if want, got := x%two48 == 0, divisible_int64_2to48(x); got != want {
+ t.Errorf("divisible_int64_2to48(%d) = %v want %v", x, got, want)
+ }
+
+ if want, got := x%two57 == 0, divisible_int64_2to57(x); got != want {
+ t.Errorf("divisible_int64_2to57(%d) = %v want %v", x, got, want)
+ }
+ }
+}
+
+func div6_uint8(n uint8) bool {
+ return n%6 == 0
+}
+
+//go:noinline
+func div6_uint16(n uint16) bool {
+ return n%6 == 0
+}
+
+//go:noinline
+func div6_uint32(n uint32) bool {
+ return n%6 == 0
+}
+
+//go:noinline
+func div6_uint64(n uint64) bool {
+ return n%6 == 0
+}
+
+//go:noinline
+func div19_uint8(n uint8) bool {
+ return n%19 == 0
+}
+
+//go:noinline
+func div19_uint16(n uint16) bool {
+ return n%19 == 0
+}
+
+//go:noinline
+func div19_uint32(n uint32) bool {
+ return n%19 == 0
+}
+
+//go:noinline
+func div19_uint64(n uint64) bool {
+ return n%19 == 0
+}
+
+//go:noinline
+func div6_int8(n int8) bool {
+ return n%6 == 0
+}
+
+//go:noinline
+func div6_int16(n int16) bool {
+ return n%6 == 0
+}
+
+//go:noinline
+func div6_int32(n int32) bool {
+ return n%6 == 0
+}
+
+//go:noinline
+func div6_int64(n int64) bool {
+ return n%6 == 0
+}
+
+//go:noinline
+func div19_int8(n int8) bool {
+ return n%19 == 0
+}
+
+//go:noinline
+func div19_int16(n int16) bool {
+ return n%19 == 0
+}
+
+//go:noinline
+func div19_int32(n int32) bool {
+ return n%19 == 0
+}
+
+//go:noinline
+func div19_int64(n int64) bool {
+ return n%19 == 0
+}
+
+// testDivisibility confirms that rewrite rules x%c ==0 for c constant are correct.
+func testDivisibility(t *testing.T) {
+ // unsigned tests
+ // test an even and an odd divisor
+ var sixU, nineteenU uint64 = 6, 19
+ // test all inputs for uint8, uint16
+ for i := uint64(0); i <= math.MaxUint16; i++ {
+ if i <= math.MaxUint8 {
+ if want, got := uint8(i)%uint8(sixU) == 0, div6_uint8(uint8(i)); got != want {
+ t.Errorf("div6_uint8(%d) = %v want %v", i, got, want)
+ }
+ if want, got := uint8(i)%uint8(nineteenU) == 0, div19_uint8(uint8(i)); got != want {
+ t.Errorf("div6_uint19(%d) = %v want %v", i, got, want)
+ }
+ }
+ if want, got := uint16(i)%uint16(sixU) == 0, div6_uint16(uint16(i)); got != want {
+ t.Errorf("div6_uint16(%d) = %v want %v", i, got, want)
+ }
+ if want, got := uint16(i)%uint16(nineteenU) == 0, div19_uint16(uint16(i)); got != want {
+ t.Errorf("div19_uint16(%d) = %v want %v", i, got, want)
+ }
+ }
+ var maxU32, maxU64 uint64 = math.MaxUint32, math.MaxUint64
+ // spot check inputs for uint32 and uint64
+ xu := []uint64{
+ 0, 1, 2, 3, 4, 5,
+ sixU, 2 * sixU, 3 * sixU, 5 * sixU, 12345 * sixU,
+ sixU + 1, 2*sixU - 5, 3*sixU + 3, 5*sixU + 4, 12345*sixU - 2,
+ nineteenU, 2 * nineteenU, 3 * nineteenU, 5 * nineteenU, 12345 * nineteenU,
+ nineteenU + 1, 2*nineteenU - 5, 3*nineteenU + 3, 5*nineteenU + 4, 12345*nineteenU - 2,
+ maxU32, maxU32 - 1, maxU32 - 2, maxU32 - 3, maxU32 - 4,
+ maxU32 - 5, maxU32 - 6, maxU32 - 7, maxU32 - 8,
+ maxU32 - 9, maxU32 - 10, maxU32 - 11, maxU32 - 12,
+ maxU32 - 13, maxU32 - 14, maxU32 - 15, maxU32 - 16,
+ maxU32 - 17, maxU32 - 18, maxU32 - 19, maxU32 - 20,
+ maxU64, maxU64 - 1, maxU64 - 2, maxU64 - 3, maxU64 - 4,
+ maxU64 - 5, maxU64 - 6, maxU64 - 7, maxU64 - 8,
+ maxU64 - 9, maxU64 - 10, maxU64 - 11, maxU64 - 12,
+ maxU64 - 13, maxU64 - 14, maxU64 - 15, maxU64 - 16,
+ maxU64 - 17, maxU64 - 18, maxU64 - 19, maxU64 - 20,
+ }
+ for _, x := range xu {
+ if x <= maxU32 {
+ if want, got := uint32(x)%uint32(sixU) == 0, div6_uint32(uint32(x)); got != want {
+ t.Errorf("div6_uint32(%d) = %v want %v", x, got, want)
+ }
+ if want, got := uint32(x)%uint32(nineteenU) == 0, div19_uint32(uint32(x)); got != want {
+ t.Errorf("div19_uint32(%d) = %v want %v", x, got, want)
+ }
+ }
+ if want, got := x%sixU == 0, div6_uint64(x); got != want {
+ t.Errorf("div6_uint64(%d) = %v want %v", x, got, want)
+ }
+ if want, got := x%nineteenU == 0, div19_uint64(x); got != want {
+ t.Errorf("div19_uint64(%d) = %v want %v", x, got, want)
+ }
+ }
+
+ // signed tests
+ // test an even and an odd divisor
+ var sixS, nineteenS int64 = 6, 19
+ // test all inputs for int8, int16
+ for i := int64(math.MinInt16); i <= math.MaxInt16; i++ {
+ if math.MinInt8 <= i && i <= math.MaxInt8 {
+ if want, got := int8(i)%int8(sixS) == 0, div6_int8(int8(i)); got != want {
+ t.Errorf("div6_int8(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int8(i)%int8(nineteenS) == 0, div19_int8(int8(i)); got != want {
+ t.Errorf("div6_int19(%d) = %v want %v", i, got, want)
+ }
+ }
+ if want, got := int16(i)%int16(sixS) == 0, div6_int16(int16(i)); got != want {
+ t.Errorf("div6_int16(%d) = %v want %v", i, got, want)
+ }
+ if want, got := int16(i)%int16(nineteenS) == 0, div19_int16(int16(i)); got != want {
+ t.Errorf("div19_int16(%d) = %v want %v", i, got, want)
+ }
+ }
+ var minI32, maxI32, minI64, maxI64 int64 = math.MinInt32, math.MaxInt32, math.MinInt64, math.MaxInt64
+ // spot check inputs for int32 and int64
+ xs := []int64{
+ 0, 1, 2, 3, 4, 5,
+ -1, -2, -3, -4, -5,
+ sixS, 2 * sixS, 3 * sixS, 5 * sixS, 12345 * sixS,
+ sixS + 1, 2*sixS - 5, 3*sixS + 3, 5*sixS + 4, 12345*sixS - 2,
+ -sixS, -2 * sixS, -3 * sixS, -5 * sixS, -12345 * sixS,
+ -sixS + 1, -2*sixS - 5, -3*sixS + 3, -5*sixS + 4, -12345*sixS - 2,
+ nineteenS, 2 * nineteenS, 3 * nineteenS, 5 * nineteenS, 12345 * nineteenS,
+ nineteenS + 1, 2*nineteenS - 5, 3*nineteenS + 3, 5*nineteenS + 4, 12345*nineteenS - 2,
+ -nineteenS, -2 * nineteenS, -3 * nineteenS, -5 * nineteenS, -12345 * nineteenS,
+ -nineteenS + 1, -2*nineteenS - 5, -3*nineteenS + 3, -5*nineteenS + 4, -12345*nineteenS - 2,
+ minI32, minI32 + 1, minI32 + 2, minI32 + 3, minI32 + 4,
+ minI32 + 5, minI32 + 6, minI32 + 7, minI32 + 8,
+ minI32 + 9, minI32 + 10, minI32 + 11, minI32 + 12,
+ minI32 + 13, minI32 + 14, minI32 + 15, minI32 + 16,
+ minI32 + 17, minI32 + 18, minI32 + 19, minI32 + 20,
+ maxI32, maxI32 - 1, maxI32 - 2, maxI32 - 3, maxI32 - 4,
+ maxI32 - 5, maxI32 - 6, maxI32 - 7, maxI32 - 8,
+ maxI32 - 9, maxI32 - 10, maxI32 - 11, maxI32 - 12,
+ maxI32 - 13, maxI32 - 14, maxI32 - 15, maxI32 - 16,
+ maxI32 - 17, maxI32 - 18, maxI32 - 19, maxI32 - 20,
+ minI64, minI64 + 1, minI64 + 2, minI64 + 3, minI64 + 4,
+ minI64 + 5, minI64 + 6, minI64 + 7, minI64 + 8,
+ minI64 + 9, minI64 + 10, minI64 + 11, minI64 + 12,
+ minI64 + 13, minI64 + 14, minI64 + 15, minI64 + 16,
+ minI64 + 17, minI64 + 18, minI64 + 19, minI64 + 20,
+ maxI64, maxI64 - 1, maxI64 - 2, maxI64 - 3, maxI64 - 4,
+ maxI64 - 5, maxI64 - 6, maxI64 - 7, maxI64 - 8,
+ maxI64 - 9, maxI64 - 10, maxI64 - 11, maxI64 - 12,
+ maxI64 - 13, maxI64 - 14, maxI64 - 15, maxI64 - 16,
+ maxI64 - 17, maxI64 - 18, maxI64 - 19, maxI64 - 20,
+ }
+ for _, x := range xs {
+ if minI32 <= x && x <= maxI32 {
+ if want, got := int32(x)%int32(sixS) == 0, div6_int32(int32(x)); got != want {
+ t.Errorf("div6_int32(%d) = %v want %v", x, got, want)
+ }
+ if want, got := int32(x)%int32(nineteenS) == 0, div19_int32(int32(x)); got != want {
+ t.Errorf("div19_int32(%d) = %v want %v", x, got, want)
+ }
+ }
+ if want, got := x%sixS == 0, div6_int64(x); got != want {
+ t.Errorf("div6_int64(%d) = %v want %v", x, got, want)
+ }
+ if want, got := x%nineteenS == 0, div19_int64(x); got != want {
+ t.Errorf("div19_int64(%d) = %v want %v", x, got, want)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/array_test.go b/src/cmd/compile/internal/gc/testdata/array_test.go
new file mode 100644
index 0000000..efa00d0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/array_test.go
@@ -0,0 +1,132 @@
+package main
+
+import "testing"
+
+//go:noinline
+func testSliceLenCap12_ssa(a [10]int, i, j int) (int, int) {
+ b := a[i:j]
+ return len(b), cap(b)
+}
+
+//go:noinline
+func testSliceLenCap1_ssa(a [10]int, i, j int) (int, int) {
+ b := a[i:]
+ return len(b), cap(b)
+}
+
+//go:noinline
+func testSliceLenCap2_ssa(a [10]int, i, j int) (int, int) {
+ b := a[:j]
+ return len(b), cap(b)
+}
+
+func testSliceLenCap(t *testing.T) {
+ a := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+ tests := [...]struct {
+ fn func(a [10]int, i, j int) (int, int)
+ i, j int // slice range
+ l, c int // len, cap
+ }{
+ // -1 means the value is not used.
+ {testSliceLenCap12_ssa, 0, 0, 0, 10},
+ {testSliceLenCap12_ssa, 0, 1, 1, 10},
+ {testSliceLenCap12_ssa, 0, 10, 10, 10},
+ {testSliceLenCap12_ssa, 10, 10, 0, 0},
+ {testSliceLenCap12_ssa, 0, 5, 5, 10},
+ {testSliceLenCap12_ssa, 5, 5, 0, 5},
+ {testSliceLenCap12_ssa, 5, 10, 5, 5},
+ {testSliceLenCap1_ssa, 0, -1, 0, 10},
+ {testSliceLenCap1_ssa, 5, -1, 5, 5},
+ {testSliceLenCap1_ssa, 10, -1, 0, 0},
+ {testSliceLenCap2_ssa, -1, 0, 0, 10},
+ {testSliceLenCap2_ssa, -1, 5, 5, 10},
+ {testSliceLenCap2_ssa, -1, 10, 10, 10},
+ }
+
+ for i, test := range tests {
+ if l, c := test.fn(a, test.i, test.j); l != test.l && c != test.c {
+ t.Errorf("#%d len(a[%d:%d]), cap(a[%d:%d]) = %d %d, want %d %d", i, test.i, test.j, test.i, test.j, l, c, test.l, test.c)
+ }
+ }
+}
+
+//go:noinline
+func testSliceGetElement_ssa(a [10]int, i, j, p int) int {
+ return a[i:j][p]
+}
+
+func testSliceGetElement(t *testing.T) {
+ a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
+ tests := [...]struct {
+ i, j, p int
+ want int // a[i:j][p]
+ }{
+ {0, 10, 2, 20},
+ {0, 5, 4, 40},
+ {5, 10, 3, 80},
+ {1, 9, 7, 80},
+ }
+
+ for i, test := range tests {
+ if got := testSliceGetElement_ssa(a, test.i, test.j, test.p); got != test.want {
+ t.Errorf("#%d a[%d:%d][%d] = %d, wanted %d", i, test.i, test.j, test.p, got, test.want)
+ }
+ }
+}
+
+//go:noinline
+func testSliceSetElement_ssa(a *[10]int, i, j, p, x int) {
+ (*a)[i:j][p] = x
+}
+
+func testSliceSetElement(t *testing.T) {
+ a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
+ tests := [...]struct {
+ i, j, p int
+ want int // a[i:j][p]
+ }{
+ {0, 10, 2, 17},
+ {0, 5, 4, 11},
+ {5, 10, 3, 28},
+ {1, 9, 7, 99},
+ }
+
+ for i, test := range tests {
+ testSliceSetElement_ssa(&a, test.i, test.j, test.p, test.want)
+ if got := a[test.i+test.p]; got != test.want {
+ t.Errorf("#%d a[%d:%d][%d] = %d, wanted %d", i, test.i, test.j, test.p, got, test.want)
+ }
+ }
+}
+
+func testSlicePanic1(t *testing.T) {
+ defer func() {
+ if r := recover(); r != nil {
+ //println("panicked as expected")
+ }
+ }()
+
+ a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
+ testSliceLenCap12_ssa(a, 3, 12)
+ t.Errorf("expected to panic, but didn't")
+}
+
+func testSlicePanic2(t *testing.T) {
+ defer func() {
+ if r := recover(); r != nil {
+ //println("panicked as expected")
+ }
+ }()
+
+ a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
+ testSliceGetElement_ssa(a, 3, 7, 4)
+ t.Errorf("expected to panic, but didn't")
+}
+
+func TestArray(t *testing.T) {
+ testSliceLenCap(t)
+ testSliceGetElement(t)
+ testSliceSetElement(t)
+ testSlicePanic1(t)
+ testSlicePanic2(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/assert_test.go b/src/cmd/compile/internal/gc/testdata/assert_test.go
new file mode 100644
index 0000000..4326be8
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/assert_test.go
@@ -0,0 +1,128 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests type assertion expressions and statements
+
+package main
+
+import (
+ "runtime"
+ "testing"
+)
+
+type (
+ S struct{}
+ U struct{}
+
+ I interface {
+ F()
+ }
+)
+
+var (
+ s *S
+ u *U
+)
+
+func (s *S) F() {}
+func (u *U) F() {}
+
+func e2t_ssa(e interface{}) *U {
+ return e.(*U)
+}
+
+func i2t_ssa(i I) *U {
+ return i.(*U)
+}
+
+func testAssertE2TOk(t *testing.T) {
+ if got := e2t_ssa(u); got != u {
+ t.Errorf("e2t_ssa(u)=%v want %v", got, u)
+ }
+}
+
+func testAssertE2TPanic(t *testing.T) {
+ var got *U
+ defer func() {
+ if got != nil {
+ t.Errorf("e2t_ssa(s)=%v want nil", got)
+ }
+ e := recover()
+ err, ok := e.(*runtime.TypeAssertionError)
+ if !ok {
+ t.Errorf("e2t_ssa(s) panic type %T", e)
+ }
+ want := "interface conversion: interface {} is *main.S, not *main.U"
+ if err.Error() != want {
+ t.Errorf("e2t_ssa(s) wrong error, want '%s', got '%s'", want, err.Error())
+ }
+ }()
+ got = e2t_ssa(s)
+ t.Errorf("e2t_ssa(s) should panic")
+
+}
+
+func testAssertI2TOk(t *testing.T) {
+ if got := i2t_ssa(u); got != u {
+ t.Errorf("i2t_ssa(u)=%v want %v", got, u)
+ }
+}
+
+func testAssertI2TPanic(t *testing.T) {
+ var got *U
+ defer func() {
+ if got != nil {
+ t.Errorf("i2t_ssa(s)=%v want nil", got)
+ }
+ e := recover()
+ err, ok := e.(*runtime.TypeAssertionError)
+ if !ok {
+ t.Errorf("i2t_ssa(s) panic type %T", e)
+ }
+ want := "interface conversion: main.I is *main.S, not *main.U"
+ if err.Error() != want {
+ t.Errorf("i2t_ssa(s) wrong error, want '%s', got '%s'", want, err.Error())
+ }
+ }()
+ got = i2t_ssa(s)
+ t.Errorf("i2t_ssa(s) should panic")
+}
+
+func e2t2_ssa(e interface{}) (*U, bool) {
+ u, ok := e.(*U)
+ return u, ok
+}
+
+func i2t2_ssa(i I) (*U, bool) {
+ u, ok := i.(*U)
+ return u, ok
+}
+
+func testAssertE2T2(t *testing.T) {
+ if got, ok := e2t2_ssa(u); !ok || got != u {
+ t.Errorf("e2t2_ssa(u)=(%v, %v) want (%v, %v)", got, ok, u, true)
+ }
+ if got, ok := e2t2_ssa(s); ok || got != nil {
+ t.Errorf("e2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false)
+ }
+}
+
+func testAssertI2T2(t *testing.T) {
+ if got, ok := i2t2_ssa(u); !ok || got != u {
+ t.Errorf("i2t2_ssa(u)=(%v, %v) want (%v, %v)", got, ok, u, true)
+ }
+ if got, ok := i2t2_ssa(s); ok || got != nil {
+ t.Errorf("i2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false)
+ }
+}
+
+// TestTypeAssertion tests type assertions.
+func TestTypeAssertion(t *testing.T) {
+ testAssertE2TOk(t)
+ testAssertE2TPanic(t)
+ testAssertI2TOk(t)
+ testAssertI2TPanic(t)
+ testAssertE2T2(t)
+ testAssertI2T2(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/break_test.go b/src/cmd/compile/internal/gc/testdata/break_test.go
new file mode 100644
index 0000000..50245df
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/break_test.go
@@ -0,0 +1,250 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests continue and break.
+
+package main
+
+import "testing"
+
+func continuePlain_ssa() int {
+ var n int
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ continue
+ }
+ n = i
+ }
+ return n
+}
+
+func continueLabeled_ssa() int {
+ var n int
+Next:
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ continue Next
+ }
+ n = i
+ }
+ return n
+}
+
+func continuePlainInner_ssa() int {
+ var n int
+ for j := 0; j < 30; j += 10 {
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ continue
+ }
+ n = i
+ }
+ n += j
+ }
+ return n
+}
+
+func continueLabeledInner_ssa() int {
+ var n int
+ for j := 0; j < 30; j += 10 {
+ Next:
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ continue Next
+ }
+ n = i
+ }
+ n += j
+ }
+ return n
+}
+
+func continueLabeledOuter_ssa() int {
+ var n int
+Next:
+ for j := 0; j < 30; j += 10 {
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ continue Next
+ }
+ n = i
+ }
+ n += j
+ }
+ return n
+}
+
+func breakPlain_ssa() int {
+ var n int
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ break
+ }
+ n = i
+ }
+ return n
+}
+
+func breakLabeled_ssa() int {
+ var n int
+Next:
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ break Next
+ }
+ n = i
+ }
+ return n
+}
+
+func breakPlainInner_ssa() int {
+ var n int
+ for j := 0; j < 30; j += 10 {
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ break
+ }
+ n = i
+ }
+ n += j
+ }
+ return n
+}
+
+func breakLabeledInner_ssa() int {
+ var n int
+ for j := 0; j < 30; j += 10 {
+ Next:
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ break Next
+ }
+ n = i
+ }
+ n += j
+ }
+ return n
+}
+
+func breakLabeledOuter_ssa() int {
+ var n int
+Next:
+ for j := 0; j < 30; j += 10 {
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ break Next
+ }
+ n = i
+ }
+ n += j
+ }
+ return n
+}
+
+var g, h int // globals to ensure optimizations don't collapse our switch statements
+
+func switchPlain_ssa() int {
+ var n int
+ switch g {
+ case 0:
+ n = 1
+ break
+ n = 2
+ }
+ return n
+}
+
+func switchLabeled_ssa() int {
+ var n int
+Done:
+ switch g {
+ case 0:
+ n = 1
+ break Done
+ n = 2
+ }
+ return n
+}
+
+func switchPlainInner_ssa() int {
+ var n int
+ switch g {
+ case 0:
+ n = 1
+ switch h {
+ case 0:
+ n += 10
+ break
+ }
+ n = 2
+ }
+ return n
+}
+
+func switchLabeledInner_ssa() int {
+ var n int
+ switch g {
+ case 0:
+ n = 1
+ Done:
+ switch h {
+ case 0:
+ n += 10
+ break Done
+ }
+ n = 2
+ }
+ return n
+}
+
+func switchLabeledOuter_ssa() int {
+ var n int
+Done:
+ switch g {
+ case 0:
+ n = 1
+ switch h {
+ case 0:
+ n += 10
+ break Done
+ }
+ n = 2
+ }
+ return n
+}
+
+// TestBreakContinue tests that continue and break statements do what they say.
+func TestBreakContinue(t *testing.T) {
+ tests := [...]struct {
+ name string
+ fn func() int
+ want int
+ }{
+ {"continuePlain_ssa", continuePlain_ssa, 9},
+ {"continueLabeled_ssa", continueLabeled_ssa, 9},
+ {"continuePlainInner_ssa", continuePlainInner_ssa, 29},
+ {"continueLabeledInner_ssa", continueLabeledInner_ssa, 29},
+ {"continueLabeledOuter_ssa", continueLabeledOuter_ssa, 5},
+
+ {"breakPlain_ssa", breakPlain_ssa, 5},
+ {"breakLabeled_ssa", breakLabeled_ssa, 5},
+ {"breakPlainInner_ssa", breakPlainInner_ssa, 25},
+ {"breakLabeledInner_ssa", breakLabeledInner_ssa, 25},
+ {"breakLabeledOuter_ssa", breakLabeledOuter_ssa, 5},
+
+ {"switchPlain_ssa", switchPlain_ssa, 1},
+ {"switchLabeled_ssa", switchLabeled_ssa, 1},
+ {"switchPlainInner_ssa", switchPlainInner_ssa, 2},
+ {"switchLabeledInner_ssa", switchLabeledInner_ssa, 2},
+ {"switchLabeledOuter_ssa", switchLabeledOuter_ssa, 11},
+
+ // no select tests; they're identical to switch
+ }
+
+ for _, test := range tests {
+ if got := test.fn(); got != test.want {
+ t.Errorf("%s()=%d, want %d", test.name, got, test.want)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/chan_test.go b/src/cmd/compile/internal/gc/testdata/chan_test.go
new file mode 100644
index 0000000..628bd8f
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/chan_test.go
@@ -0,0 +1,63 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// chan.go tests chan operations.
+package main
+
+import "testing"
+
+//go:noinline
+func lenChan_ssa(v chan int) int {
+ return len(v)
+}
+
+//go:noinline
+func capChan_ssa(v chan int) int {
+ return cap(v)
+}
+
+func testLenChan(t *testing.T) {
+
+ v := make(chan int, 10)
+ v <- 1
+ v <- 1
+ v <- 1
+
+ if want, got := 3, lenChan_ssa(v); got != want {
+ t.Errorf("expected len(chan) = %d, got %d", want, got)
+ }
+}
+
+func testLenNilChan(t *testing.T) {
+
+ var v chan int
+ if want, got := 0, lenChan_ssa(v); got != want {
+ t.Errorf("expected len(nil) = %d, got %d", want, got)
+ }
+}
+
+func testCapChan(t *testing.T) {
+
+ v := make(chan int, 25)
+
+ if want, got := 25, capChan_ssa(v); got != want {
+ t.Errorf("expected cap(chan) = %d, got %d", want, got)
+ }
+}
+
+func testCapNilChan(t *testing.T) {
+
+ var v chan int
+ if want, got := 0, capChan_ssa(v); got != want {
+ t.Errorf("expected cap(nil) = %d, got %d", want, got)
+ }
+}
+
+func TestChan(t *testing.T) {
+ testLenChan(t)
+ testLenNilChan(t)
+
+ testCapChan(t)
+ testCapNilChan(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/closure_test.go b/src/cmd/compile/internal/gc/testdata/closure_test.go
new file mode 100644
index 0000000..6cddc2d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/closure_test.go
@@ -0,0 +1,32 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// closure.go tests closure operations.
+package main
+
+import "testing"
+
+//go:noinline
+func testCFunc_ssa() int {
+ a := 0
+ b := func() {
+ switch {
+ }
+ a++
+ }
+ b()
+ b()
+ return a
+}
+
+func testCFunc(t *testing.T) {
+ if want, got := 2, testCFunc_ssa(); got != want {
+ t.Errorf("expected %d, got %d", want, got)
+ }
+}
+
+// TestClosure tests closure related behavior.
+func TestClosure(t *testing.T) {
+ testCFunc(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/cmpConst_test.go b/src/cmd/compile/internal/gc/testdata/cmpConst_test.go
new file mode 100644
index 0000000..9400ef4
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/cmpConst_test.go
@@ -0,0 +1,2209 @@
+// Code generated by gen/cmpConstGen.go. DO NOT EDIT.
+
+package main
+
+import (
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+// results show the expected result for the elements left of, equal to and right of the index.
+type result struct{ l, e, r bool }
+
+var (
+ eq = result{l: false, e: true, r: false}
+ ne = result{l: true, e: false, r: true}
+ lt = result{l: true, e: false, r: false}
+ le = result{l: true, e: true, r: false}
+ gt = result{l: false, e: false, r: true}
+ ge = result{l: false, e: true, r: true}
+)
+
+// uint64 tests
+var uint64_vals = []uint64{
+ 0,
+ 1,
+ 126,
+ 127,
+ 128,
+ 254,
+ 255,
+ 256,
+ 32766,
+ 32767,
+ 32768,
+ 65534,
+ 65535,
+ 65536,
+ 2147483646,
+ 2147483647,
+ 2147483648,
+ 4278190080,
+ 4294967294,
+ 4294967295,
+ 4294967296,
+ 1095216660480,
+ 9223372036854775806,
+ 9223372036854775807,
+ 9223372036854775808,
+ 18374686479671623680,
+ 18446744073709551614,
+ 18446744073709551615,
+}
+
+func lt_0_uint64(x uint64) bool { return x < 0 }
+func le_0_uint64(x uint64) bool { return x <= 0 }
+func gt_0_uint64(x uint64) bool { return x > 0 }
+func ge_0_uint64(x uint64) bool { return x >= 0 }
+func eq_0_uint64(x uint64) bool { return x == 0 }
+func ne_0_uint64(x uint64) bool { return x != 0 }
+func lt_1_uint64(x uint64) bool { return x < 1 }
+func le_1_uint64(x uint64) bool { return x <= 1 }
+func gt_1_uint64(x uint64) bool { return x > 1 }
+func ge_1_uint64(x uint64) bool { return x >= 1 }
+func eq_1_uint64(x uint64) bool { return x == 1 }
+func ne_1_uint64(x uint64) bool { return x != 1 }
+func lt_126_uint64(x uint64) bool { return x < 126 }
+func le_126_uint64(x uint64) bool { return x <= 126 }
+func gt_126_uint64(x uint64) bool { return x > 126 }
+func ge_126_uint64(x uint64) bool { return x >= 126 }
+func eq_126_uint64(x uint64) bool { return x == 126 }
+func ne_126_uint64(x uint64) bool { return x != 126 }
+func lt_127_uint64(x uint64) bool { return x < 127 }
+func le_127_uint64(x uint64) bool { return x <= 127 }
+func gt_127_uint64(x uint64) bool { return x > 127 }
+func ge_127_uint64(x uint64) bool { return x >= 127 }
+func eq_127_uint64(x uint64) bool { return x == 127 }
+func ne_127_uint64(x uint64) bool { return x != 127 }
+func lt_128_uint64(x uint64) bool { return x < 128 }
+func le_128_uint64(x uint64) bool { return x <= 128 }
+func gt_128_uint64(x uint64) bool { return x > 128 }
+func ge_128_uint64(x uint64) bool { return x >= 128 }
+func eq_128_uint64(x uint64) bool { return x == 128 }
+func ne_128_uint64(x uint64) bool { return x != 128 }
+func lt_254_uint64(x uint64) bool { return x < 254 }
+func le_254_uint64(x uint64) bool { return x <= 254 }
+func gt_254_uint64(x uint64) bool { return x > 254 }
+func ge_254_uint64(x uint64) bool { return x >= 254 }
+func eq_254_uint64(x uint64) bool { return x == 254 }
+func ne_254_uint64(x uint64) bool { return x != 254 }
+func lt_255_uint64(x uint64) bool { return x < 255 }
+func le_255_uint64(x uint64) bool { return x <= 255 }
+func gt_255_uint64(x uint64) bool { return x > 255 }
+func ge_255_uint64(x uint64) bool { return x >= 255 }
+func eq_255_uint64(x uint64) bool { return x == 255 }
+func ne_255_uint64(x uint64) bool { return x != 255 }
+func lt_256_uint64(x uint64) bool { return x < 256 }
+func le_256_uint64(x uint64) bool { return x <= 256 }
+func gt_256_uint64(x uint64) bool { return x > 256 }
+func ge_256_uint64(x uint64) bool { return x >= 256 }
+func eq_256_uint64(x uint64) bool { return x == 256 }
+func ne_256_uint64(x uint64) bool { return x != 256 }
+func lt_32766_uint64(x uint64) bool { return x < 32766 }
+func le_32766_uint64(x uint64) bool { return x <= 32766 }
+func gt_32766_uint64(x uint64) bool { return x > 32766 }
+func ge_32766_uint64(x uint64) bool { return x >= 32766 }
+func eq_32766_uint64(x uint64) bool { return x == 32766 }
+func ne_32766_uint64(x uint64) bool { return x != 32766 }
+func lt_32767_uint64(x uint64) bool { return x < 32767 }
+func le_32767_uint64(x uint64) bool { return x <= 32767 }
+func gt_32767_uint64(x uint64) bool { return x > 32767 }
+func ge_32767_uint64(x uint64) bool { return x >= 32767 }
+func eq_32767_uint64(x uint64) bool { return x == 32767 }
+func ne_32767_uint64(x uint64) bool { return x != 32767 }
+func lt_32768_uint64(x uint64) bool { return x < 32768 }
+func le_32768_uint64(x uint64) bool { return x <= 32768 }
+func gt_32768_uint64(x uint64) bool { return x > 32768 }
+func ge_32768_uint64(x uint64) bool { return x >= 32768 }
+func eq_32768_uint64(x uint64) bool { return x == 32768 }
+func ne_32768_uint64(x uint64) bool { return x != 32768 }
+func lt_65534_uint64(x uint64) bool { return x < 65534 }
+func le_65534_uint64(x uint64) bool { return x <= 65534 }
+func gt_65534_uint64(x uint64) bool { return x > 65534 }
+func ge_65534_uint64(x uint64) bool { return x >= 65534 }
+func eq_65534_uint64(x uint64) bool { return x == 65534 }
+func ne_65534_uint64(x uint64) bool { return x != 65534 }
+func lt_65535_uint64(x uint64) bool { return x < 65535 }
+func le_65535_uint64(x uint64) bool { return x <= 65535 }
+func gt_65535_uint64(x uint64) bool { return x > 65535 }
+func ge_65535_uint64(x uint64) bool { return x >= 65535 }
+func eq_65535_uint64(x uint64) bool { return x == 65535 }
+func ne_65535_uint64(x uint64) bool { return x != 65535 }
+func lt_65536_uint64(x uint64) bool { return x < 65536 }
+func le_65536_uint64(x uint64) bool { return x <= 65536 }
+func gt_65536_uint64(x uint64) bool { return x > 65536 }
+func ge_65536_uint64(x uint64) bool { return x >= 65536 }
+func eq_65536_uint64(x uint64) bool { return x == 65536 }
+func ne_65536_uint64(x uint64) bool { return x != 65536 }
+func lt_2147483646_uint64(x uint64) bool { return x < 2147483646 }
+func le_2147483646_uint64(x uint64) bool { return x <= 2147483646 }
+func gt_2147483646_uint64(x uint64) bool { return x > 2147483646 }
+func ge_2147483646_uint64(x uint64) bool { return x >= 2147483646 }
+func eq_2147483646_uint64(x uint64) bool { return x == 2147483646 }
+func ne_2147483646_uint64(x uint64) bool { return x != 2147483646 }
+func lt_2147483647_uint64(x uint64) bool { return x < 2147483647 }
+func le_2147483647_uint64(x uint64) bool { return x <= 2147483647 }
+func gt_2147483647_uint64(x uint64) bool { return x > 2147483647 }
+func ge_2147483647_uint64(x uint64) bool { return x >= 2147483647 }
+func eq_2147483647_uint64(x uint64) bool { return x == 2147483647 }
+func ne_2147483647_uint64(x uint64) bool { return x != 2147483647 }
+func lt_2147483648_uint64(x uint64) bool { return x < 2147483648 }
+func le_2147483648_uint64(x uint64) bool { return x <= 2147483648 }
+func gt_2147483648_uint64(x uint64) bool { return x > 2147483648 }
+func ge_2147483648_uint64(x uint64) bool { return x >= 2147483648 }
+func eq_2147483648_uint64(x uint64) bool { return x == 2147483648 }
+func ne_2147483648_uint64(x uint64) bool { return x != 2147483648 }
+func lt_4278190080_uint64(x uint64) bool { return x < 4278190080 }
+func le_4278190080_uint64(x uint64) bool { return x <= 4278190080 }
+func gt_4278190080_uint64(x uint64) bool { return x > 4278190080 }
+func ge_4278190080_uint64(x uint64) bool { return x >= 4278190080 }
+func eq_4278190080_uint64(x uint64) bool { return x == 4278190080 }
+func ne_4278190080_uint64(x uint64) bool { return x != 4278190080 }
+func lt_4294967294_uint64(x uint64) bool { return x < 4294967294 }
+func le_4294967294_uint64(x uint64) bool { return x <= 4294967294 }
+func gt_4294967294_uint64(x uint64) bool { return x > 4294967294 }
+func ge_4294967294_uint64(x uint64) bool { return x >= 4294967294 }
+func eq_4294967294_uint64(x uint64) bool { return x == 4294967294 }
+func ne_4294967294_uint64(x uint64) bool { return x != 4294967294 }
+func lt_4294967295_uint64(x uint64) bool { return x < 4294967295 }
+func le_4294967295_uint64(x uint64) bool { return x <= 4294967295 }
+func gt_4294967295_uint64(x uint64) bool { return x > 4294967295 }
+func ge_4294967295_uint64(x uint64) bool { return x >= 4294967295 }
+func eq_4294967295_uint64(x uint64) bool { return x == 4294967295 }
+func ne_4294967295_uint64(x uint64) bool { return x != 4294967295 }
+func lt_4294967296_uint64(x uint64) bool { return x < 4294967296 }
+func le_4294967296_uint64(x uint64) bool { return x <= 4294967296 }
+func gt_4294967296_uint64(x uint64) bool { return x > 4294967296 }
+func ge_4294967296_uint64(x uint64) bool { return x >= 4294967296 }
+func eq_4294967296_uint64(x uint64) bool { return x == 4294967296 }
+func ne_4294967296_uint64(x uint64) bool { return x != 4294967296 }
+func lt_1095216660480_uint64(x uint64) bool { return x < 1095216660480 }
+func le_1095216660480_uint64(x uint64) bool { return x <= 1095216660480 }
+func gt_1095216660480_uint64(x uint64) bool { return x > 1095216660480 }
+func ge_1095216660480_uint64(x uint64) bool { return x >= 1095216660480 }
+func eq_1095216660480_uint64(x uint64) bool { return x == 1095216660480 }
+func ne_1095216660480_uint64(x uint64) bool { return x != 1095216660480 }
+func lt_9223372036854775806_uint64(x uint64) bool { return x < 9223372036854775806 }
+func le_9223372036854775806_uint64(x uint64) bool { return x <= 9223372036854775806 }
+func gt_9223372036854775806_uint64(x uint64) bool { return x > 9223372036854775806 }
+func ge_9223372036854775806_uint64(x uint64) bool { return x >= 9223372036854775806 }
+func eq_9223372036854775806_uint64(x uint64) bool { return x == 9223372036854775806 }
+func ne_9223372036854775806_uint64(x uint64) bool { return x != 9223372036854775806 }
+func lt_9223372036854775807_uint64(x uint64) bool { return x < 9223372036854775807 }
+func le_9223372036854775807_uint64(x uint64) bool { return x <= 9223372036854775807 }
+func gt_9223372036854775807_uint64(x uint64) bool { return x > 9223372036854775807 }
+func ge_9223372036854775807_uint64(x uint64) bool { return x >= 9223372036854775807 }
+func eq_9223372036854775807_uint64(x uint64) bool { return x == 9223372036854775807 }
+func ne_9223372036854775807_uint64(x uint64) bool { return x != 9223372036854775807 }
+func lt_9223372036854775808_uint64(x uint64) bool { return x < 9223372036854775808 }
+func le_9223372036854775808_uint64(x uint64) bool { return x <= 9223372036854775808 }
+func gt_9223372036854775808_uint64(x uint64) bool { return x > 9223372036854775808 }
+func ge_9223372036854775808_uint64(x uint64) bool { return x >= 9223372036854775808 }
+func eq_9223372036854775808_uint64(x uint64) bool { return x == 9223372036854775808 }
+func ne_9223372036854775808_uint64(x uint64) bool { return x != 9223372036854775808 }
+func lt_18374686479671623680_uint64(x uint64) bool { return x < 18374686479671623680 }
+func le_18374686479671623680_uint64(x uint64) bool { return x <= 18374686479671623680 }
+func gt_18374686479671623680_uint64(x uint64) bool { return x > 18374686479671623680 }
+func ge_18374686479671623680_uint64(x uint64) bool { return x >= 18374686479671623680 }
+func eq_18374686479671623680_uint64(x uint64) bool { return x == 18374686479671623680 }
+func ne_18374686479671623680_uint64(x uint64) bool { return x != 18374686479671623680 }
+func lt_18446744073709551614_uint64(x uint64) bool { return x < 18446744073709551614 }
+func le_18446744073709551614_uint64(x uint64) bool { return x <= 18446744073709551614 }
+func gt_18446744073709551614_uint64(x uint64) bool { return x > 18446744073709551614 }
+func ge_18446744073709551614_uint64(x uint64) bool { return x >= 18446744073709551614 }
+func eq_18446744073709551614_uint64(x uint64) bool { return x == 18446744073709551614 }
+func ne_18446744073709551614_uint64(x uint64) bool { return x != 18446744073709551614 }
+func lt_18446744073709551615_uint64(x uint64) bool { return x < 18446744073709551615 }
+func le_18446744073709551615_uint64(x uint64) bool { return x <= 18446744073709551615 }
+func gt_18446744073709551615_uint64(x uint64) bool { return x > 18446744073709551615 }
+func ge_18446744073709551615_uint64(x uint64) bool { return x >= 18446744073709551615 }
+func eq_18446744073709551615_uint64(x uint64) bool { return x == 18446744073709551615 }
+func ne_18446744073709551615_uint64(x uint64) bool { return x != 18446744073709551615 }
+
+var uint64_tests = []struct {
+ idx int // index of the constant used
+ exp result // expected results
+ fn func(uint64) bool
+}{
+ {idx: 0, exp: lt, fn: lt_0_uint64},
+ {idx: 0, exp: le, fn: le_0_uint64},
+ {idx: 0, exp: gt, fn: gt_0_uint64},
+ {idx: 0, exp: ge, fn: ge_0_uint64},
+ {idx: 0, exp: eq, fn: eq_0_uint64},
+ {idx: 0, exp: ne, fn: ne_0_uint64},
+ {idx: 1, exp: lt, fn: lt_1_uint64},
+ {idx: 1, exp: le, fn: le_1_uint64},
+ {idx: 1, exp: gt, fn: gt_1_uint64},
+ {idx: 1, exp: ge, fn: ge_1_uint64},
+ {idx: 1, exp: eq, fn: eq_1_uint64},
+ {idx: 1, exp: ne, fn: ne_1_uint64},
+ {idx: 2, exp: lt, fn: lt_126_uint64},
+ {idx: 2, exp: le, fn: le_126_uint64},
+ {idx: 2, exp: gt, fn: gt_126_uint64},
+ {idx: 2, exp: ge, fn: ge_126_uint64},
+ {idx: 2, exp: eq, fn: eq_126_uint64},
+ {idx: 2, exp: ne, fn: ne_126_uint64},
+ {idx: 3, exp: lt, fn: lt_127_uint64},
+ {idx: 3, exp: le, fn: le_127_uint64},
+ {idx: 3, exp: gt, fn: gt_127_uint64},
+ {idx: 3, exp: ge, fn: ge_127_uint64},
+ {idx: 3, exp: eq, fn: eq_127_uint64},
+ {idx: 3, exp: ne, fn: ne_127_uint64},
+ {idx: 4, exp: lt, fn: lt_128_uint64},
+ {idx: 4, exp: le, fn: le_128_uint64},
+ {idx: 4, exp: gt, fn: gt_128_uint64},
+ {idx: 4, exp: ge, fn: ge_128_uint64},
+ {idx: 4, exp: eq, fn: eq_128_uint64},
+ {idx: 4, exp: ne, fn: ne_128_uint64},
+ {idx: 5, exp: lt, fn: lt_254_uint64},
+ {idx: 5, exp: le, fn: le_254_uint64},
+ {idx: 5, exp: gt, fn: gt_254_uint64},
+ {idx: 5, exp: ge, fn: ge_254_uint64},
+ {idx: 5, exp: eq, fn: eq_254_uint64},
+ {idx: 5, exp: ne, fn: ne_254_uint64},
+ {idx: 6, exp: lt, fn: lt_255_uint64},
+ {idx: 6, exp: le, fn: le_255_uint64},
+ {idx: 6, exp: gt, fn: gt_255_uint64},
+ {idx: 6, exp: ge, fn: ge_255_uint64},
+ {idx: 6, exp: eq, fn: eq_255_uint64},
+ {idx: 6, exp: ne, fn: ne_255_uint64},
+ {idx: 7, exp: lt, fn: lt_256_uint64},
+ {idx: 7, exp: le, fn: le_256_uint64},
+ {idx: 7, exp: gt, fn: gt_256_uint64},
+ {idx: 7, exp: ge, fn: ge_256_uint64},
+ {idx: 7, exp: eq, fn: eq_256_uint64},
+ {idx: 7, exp: ne, fn: ne_256_uint64},
+ {idx: 8, exp: lt, fn: lt_32766_uint64},
+ {idx: 8, exp: le, fn: le_32766_uint64},
+ {idx: 8, exp: gt, fn: gt_32766_uint64},
+ {idx: 8, exp: ge, fn: ge_32766_uint64},
+ {idx: 8, exp: eq, fn: eq_32766_uint64},
+ {idx: 8, exp: ne, fn: ne_32766_uint64},
+ {idx: 9, exp: lt, fn: lt_32767_uint64},
+ {idx: 9, exp: le, fn: le_32767_uint64},
+ {idx: 9, exp: gt, fn: gt_32767_uint64},
+ {idx: 9, exp: ge, fn: ge_32767_uint64},
+ {idx: 9, exp: eq, fn: eq_32767_uint64},
+ {idx: 9, exp: ne, fn: ne_32767_uint64},
+ {idx: 10, exp: lt, fn: lt_32768_uint64},
+ {idx: 10, exp: le, fn: le_32768_uint64},
+ {idx: 10, exp: gt, fn: gt_32768_uint64},
+ {idx: 10, exp: ge, fn: ge_32768_uint64},
+ {idx: 10, exp: eq, fn: eq_32768_uint64},
+ {idx: 10, exp: ne, fn: ne_32768_uint64},
+ {idx: 11, exp: lt, fn: lt_65534_uint64},
+ {idx: 11, exp: le, fn: le_65534_uint64},
+ {idx: 11, exp: gt, fn: gt_65534_uint64},
+ {idx: 11, exp: ge, fn: ge_65534_uint64},
+ {idx: 11, exp: eq, fn: eq_65534_uint64},
+ {idx: 11, exp: ne, fn: ne_65534_uint64},
+ {idx: 12, exp: lt, fn: lt_65535_uint64},
+ {idx: 12, exp: le, fn: le_65535_uint64},
+ {idx: 12, exp: gt, fn: gt_65535_uint64},
+ {idx: 12, exp: ge, fn: ge_65535_uint64},
+ {idx: 12, exp: eq, fn: eq_65535_uint64},
+ {idx: 12, exp: ne, fn: ne_65535_uint64},
+ {idx: 13, exp: lt, fn: lt_65536_uint64},
+ {idx: 13, exp: le, fn: le_65536_uint64},
+ {idx: 13, exp: gt, fn: gt_65536_uint64},
+ {idx: 13, exp: ge, fn: ge_65536_uint64},
+ {idx: 13, exp: eq, fn: eq_65536_uint64},
+ {idx: 13, exp: ne, fn: ne_65536_uint64},
+ {idx: 14, exp: lt, fn: lt_2147483646_uint64},
+ {idx: 14, exp: le, fn: le_2147483646_uint64},
+ {idx: 14, exp: gt, fn: gt_2147483646_uint64},
+ {idx: 14, exp: ge, fn: ge_2147483646_uint64},
+ {idx: 14, exp: eq, fn: eq_2147483646_uint64},
+ {idx: 14, exp: ne, fn: ne_2147483646_uint64},
+ {idx: 15, exp: lt, fn: lt_2147483647_uint64},
+ {idx: 15, exp: le, fn: le_2147483647_uint64},
+ {idx: 15, exp: gt, fn: gt_2147483647_uint64},
+ {idx: 15, exp: ge, fn: ge_2147483647_uint64},
+ {idx: 15, exp: eq, fn: eq_2147483647_uint64},
+ {idx: 15, exp: ne, fn: ne_2147483647_uint64},
+ {idx: 16, exp: lt, fn: lt_2147483648_uint64},
+ {idx: 16, exp: le, fn: le_2147483648_uint64},
+ {idx: 16, exp: gt, fn: gt_2147483648_uint64},
+ {idx: 16, exp: ge, fn: ge_2147483648_uint64},
+ {idx: 16, exp: eq, fn: eq_2147483648_uint64},
+ {idx: 16, exp: ne, fn: ne_2147483648_uint64},
+ {idx: 17, exp: lt, fn: lt_4278190080_uint64},
+ {idx: 17, exp: le, fn: le_4278190080_uint64},
+ {idx: 17, exp: gt, fn: gt_4278190080_uint64},
+ {idx: 17, exp: ge, fn: ge_4278190080_uint64},
+ {idx: 17, exp: eq, fn: eq_4278190080_uint64},
+ {idx: 17, exp: ne, fn: ne_4278190080_uint64},
+ {idx: 18, exp: lt, fn: lt_4294967294_uint64},
+ {idx: 18, exp: le, fn: le_4294967294_uint64},
+ {idx: 18, exp: gt, fn: gt_4294967294_uint64},
+ {idx: 18, exp: ge, fn: ge_4294967294_uint64},
+ {idx: 18, exp: eq, fn: eq_4294967294_uint64},
+ {idx: 18, exp: ne, fn: ne_4294967294_uint64},
+ {idx: 19, exp: lt, fn: lt_4294967295_uint64},
+ {idx: 19, exp: le, fn: le_4294967295_uint64},
+ {idx: 19, exp: gt, fn: gt_4294967295_uint64},
+ {idx: 19, exp: ge, fn: ge_4294967295_uint64},
+ {idx: 19, exp: eq, fn: eq_4294967295_uint64},
+ {idx: 19, exp: ne, fn: ne_4294967295_uint64},
+ {idx: 20, exp: lt, fn: lt_4294967296_uint64},
+ {idx: 20, exp: le, fn: le_4294967296_uint64},
+ {idx: 20, exp: gt, fn: gt_4294967296_uint64},
+ {idx: 20, exp: ge, fn: ge_4294967296_uint64},
+ {idx: 20, exp: eq, fn: eq_4294967296_uint64},
+ {idx: 20, exp: ne, fn: ne_4294967296_uint64},
+ {idx: 21, exp: lt, fn: lt_1095216660480_uint64},
+ {idx: 21, exp: le, fn: le_1095216660480_uint64},
+ {idx: 21, exp: gt, fn: gt_1095216660480_uint64},
+ {idx: 21, exp: ge, fn: ge_1095216660480_uint64},
+ {idx: 21, exp: eq, fn: eq_1095216660480_uint64},
+ {idx: 21, exp: ne, fn: ne_1095216660480_uint64},
+ {idx: 22, exp: lt, fn: lt_9223372036854775806_uint64},
+ {idx: 22, exp: le, fn: le_9223372036854775806_uint64},
+ {idx: 22, exp: gt, fn: gt_9223372036854775806_uint64},
+ {idx: 22, exp: ge, fn: ge_9223372036854775806_uint64},
+ {idx: 22, exp: eq, fn: eq_9223372036854775806_uint64},
+ {idx: 22, exp: ne, fn: ne_9223372036854775806_uint64},
+ {idx: 23, exp: lt, fn: lt_9223372036854775807_uint64},
+ {idx: 23, exp: le, fn: le_9223372036854775807_uint64},
+ {idx: 23, exp: gt, fn: gt_9223372036854775807_uint64},
+ {idx: 23, exp: ge, fn: ge_9223372036854775807_uint64},
+ {idx: 23, exp: eq, fn: eq_9223372036854775807_uint64},
+ {idx: 23, exp: ne, fn: ne_9223372036854775807_uint64},
+ {idx: 24, exp: lt, fn: lt_9223372036854775808_uint64},
+ {idx: 24, exp: le, fn: le_9223372036854775808_uint64},
+ {idx: 24, exp: gt, fn: gt_9223372036854775808_uint64},
+ {idx: 24, exp: ge, fn: ge_9223372036854775808_uint64},
+ {idx: 24, exp: eq, fn: eq_9223372036854775808_uint64},
+ {idx: 24, exp: ne, fn: ne_9223372036854775808_uint64},
+ {idx: 25, exp: lt, fn: lt_18374686479671623680_uint64},
+ {idx: 25, exp: le, fn: le_18374686479671623680_uint64},
+ {idx: 25, exp: gt, fn: gt_18374686479671623680_uint64},
+ {idx: 25, exp: ge, fn: ge_18374686479671623680_uint64},
+ {idx: 25, exp: eq, fn: eq_18374686479671623680_uint64},
+ {idx: 25, exp: ne, fn: ne_18374686479671623680_uint64},
+ {idx: 26, exp: lt, fn: lt_18446744073709551614_uint64},
+ {idx: 26, exp: le, fn: le_18446744073709551614_uint64},
+ {idx: 26, exp: gt, fn: gt_18446744073709551614_uint64},
+ {idx: 26, exp: ge, fn: ge_18446744073709551614_uint64},
+ {idx: 26, exp: eq, fn: eq_18446744073709551614_uint64},
+ {idx: 26, exp: ne, fn: ne_18446744073709551614_uint64},
+ {idx: 27, exp: lt, fn: lt_18446744073709551615_uint64},
+ {idx: 27, exp: le, fn: le_18446744073709551615_uint64},
+ {idx: 27, exp: gt, fn: gt_18446744073709551615_uint64},
+ {idx: 27, exp: ge, fn: ge_18446744073709551615_uint64},
+ {idx: 27, exp: eq, fn: eq_18446744073709551615_uint64},
+ {idx: 27, exp: ne, fn: ne_18446744073709551615_uint64},
+}
+
+// uint32 tests
+var uint32_vals = []uint32{
+ 0,
+ 1,
+ 126,
+ 127,
+ 128,
+ 254,
+ 255,
+ 256,
+ 32766,
+ 32767,
+ 32768,
+ 65534,
+ 65535,
+ 65536,
+ 2147483646,
+ 2147483647,
+ 2147483648,
+ 4278190080,
+ 4294967294,
+ 4294967295,
+}
+
+func lt_0_uint32(x uint32) bool { return x < 0 }
+func le_0_uint32(x uint32) bool { return x <= 0 }
+func gt_0_uint32(x uint32) bool { return x > 0 }
+func ge_0_uint32(x uint32) bool { return x >= 0 }
+func eq_0_uint32(x uint32) bool { return x == 0 }
+func ne_0_uint32(x uint32) bool { return x != 0 }
+func lt_1_uint32(x uint32) bool { return x < 1 }
+func le_1_uint32(x uint32) bool { return x <= 1 }
+func gt_1_uint32(x uint32) bool { return x > 1 }
+func ge_1_uint32(x uint32) bool { return x >= 1 }
+func eq_1_uint32(x uint32) bool { return x == 1 }
+func ne_1_uint32(x uint32) bool { return x != 1 }
+func lt_126_uint32(x uint32) bool { return x < 126 }
+func le_126_uint32(x uint32) bool { return x <= 126 }
+func gt_126_uint32(x uint32) bool { return x > 126 }
+func ge_126_uint32(x uint32) bool { return x >= 126 }
+func eq_126_uint32(x uint32) bool { return x == 126 }
+func ne_126_uint32(x uint32) bool { return x != 126 }
+func lt_127_uint32(x uint32) bool { return x < 127 }
+func le_127_uint32(x uint32) bool { return x <= 127 }
+func gt_127_uint32(x uint32) bool { return x > 127 }
+func ge_127_uint32(x uint32) bool { return x >= 127 }
+func eq_127_uint32(x uint32) bool { return x == 127 }
+func ne_127_uint32(x uint32) bool { return x != 127 }
+func lt_128_uint32(x uint32) bool { return x < 128 }
+func le_128_uint32(x uint32) bool { return x <= 128 }
+func gt_128_uint32(x uint32) bool { return x > 128 }
+func ge_128_uint32(x uint32) bool { return x >= 128 }
+func eq_128_uint32(x uint32) bool { return x == 128 }
+func ne_128_uint32(x uint32) bool { return x != 128 }
+func lt_254_uint32(x uint32) bool { return x < 254 }
+func le_254_uint32(x uint32) bool { return x <= 254 }
+func gt_254_uint32(x uint32) bool { return x > 254 }
+func ge_254_uint32(x uint32) bool { return x >= 254 }
+func eq_254_uint32(x uint32) bool { return x == 254 }
+func ne_254_uint32(x uint32) bool { return x != 254 }
+func lt_255_uint32(x uint32) bool { return x < 255 }
+func le_255_uint32(x uint32) bool { return x <= 255 }
+func gt_255_uint32(x uint32) bool { return x > 255 }
+func ge_255_uint32(x uint32) bool { return x >= 255 }
+func eq_255_uint32(x uint32) bool { return x == 255 }
+func ne_255_uint32(x uint32) bool { return x != 255 }
+func lt_256_uint32(x uint32) bool { return x < 256 }
+func le_256_uint32(x uint32) bool { return x <= 256 }
+func gt_256_uint32(x uint32) bool { return x > 256 }
+func ge_256_uint32(x uint32) bool { return x >= 256 }
+func eq_256_uint32(x uint32) bool { return x == 256 }
+func ne_256_uint32(x uint32) bool { return x != 256 }
+func lt_32766_uint32(x uint32) bool { return x < 32766 }
+func le_32766_uint32(x uint32) bool { return x <= 32766 }
+func gt_32766_uint32(x uint32) bool { return x > 32766 }
+func ge_32766_uint32(x uint32) bool { return x >= 32766 }
+func eq_32766_uint32(x uint32) bool { return x == 32766 }
+func ne_32766_uint32(x uint32) bool { return x != 32766 }
+func lt_32767_uint32(x uint32) bool { return x < 32767 }
+func le_32767_uint32(x uint32) bool { return x <= 32767 }
+func gt_32767_uint32(x uint32) bool { return x > 32767 }
+func ge_32767_uint32(x uint32) bool { return x >= 32767 }
+func eq_32767_uint32(x uint32) bool { return x == 32767 }
+func ne_32767_uint32(x uint32) bool { return x != 32767 }
+func lt_32768_uint32(x uint32) bool { return x < 32768 }
+func le_32768_uint32(x uint32) bool { return x <= 32768 }
+func gt_32768_uint32(x uint32) bool { return x > 32768 }
+func ge_32768_uint32(x uint32) bool { return x >= 32768 }
+func eq_32768_uint32(x uint32) bool { return x == 32768 }
+func ne_32768_uint32(x uint32) bool { return x != 32768 }
+func lt_65534_uint32(x uint32) bool { return x < 65534 }
+func le_65534_uint32(x uint32) bool { return x <= 65534 }
+func gt_65534_uint32(x uint32) bool { return x > 65534 }
+func ge_65534_uint32(x uint32) bool { return x >= 65534 }
+func eq_65534_uint32(x uint32) bool { return x == 65534 }
+func ne_65534_uint32(x uint32) bool { return x != 65534 }
+func lt_65535_uint32(x uint32) bool { return x < 65535 }
+func le_65535_uint32(x uint32) bool { return x <= 65535 }
+func gt_65535_uint32(x uint32) bool { return x > 65535 }
+func ge_65535_uint32(x uint32) bool { return x >= 65535 }
+func eq_65535_uint32(x uint32) bool { return x == 65535 }
+func ne_65535_uint32(x uint32) bool { return x != 65535 }
+func lt_65536_uint32(x uint32) bool { return x < 65536 }
+func le_65536_uint32(x uint32) bool { return x <= 65536 }
+func gt_65536_uint32(x uint32) bool { return x > 65536 }
+func ge_65536_uint32(x uint32) bool { return x >= 65536 }
+func eq_65536_uint32(x uint32) bool { return x == 65536 }
+func ne_65536_uint32(x uint32) bool { return x != 65536 }
+func lt_2147483646_uint32(x uint32) bool { return x < 2147483646 }
+func le_2147483646_uint32(x uint32) bool { return x <= 2147483646 }
+func gt_2147483646_uint32(x uint32) bool { return x > 2147483646 }
+func ge_2147483646_uint32(x uint32) bool { return x >= 2147483646 }
+func eq_2147483646_uint32(x uint32) bool { return x == 2147483646 }
+func ne_2147483646_uint32(x uint32) bool { return x != 2147483646 }
+func lt_2147483647_uint32(x uint32) bool { return x < 2147483647 }
+func le_2147483647_uint32(x uint32) bool { return x <= 2147483647 }
+func gt_2147483647_uint32(x uint32) bool { return x > 2147483647 }
+func ge_2147483647_uint32(x uint32) bool { return x >= 2147483647 }
+func eq_2147483647_uint32(x uint32) bool { return x == 2147483647 }
+func ne_2147483647_uint32(x uint32) bool { return x != 2147483647 }
+func lt_2147483648_uint32(x uint32) bool { return x < 2147483648 }
+func le_2147483648_uint32(x uint32) bool { return x <= 2147483648 }
+func gt_2147483648_uint32(x uint32) bool { return x > 2147483648 }
+func ge_2147483648_uint32(x uint32) bool { return x >= 2147483648 }
+func eq_2147483648_uint32(x uint32) bool { return x == 2147483648 }
+func ne_2147483648_uint32(x uint32) bool { return x != 2147483648 }
+func lt_4278190080_uint32(x uint32) bool { return x < 4278190080 }
+func le_4278190080_uint32(x uint32) bool { return x <= 4278190080 }
+func gt_4278190080_uint32(x uint32) bool { return x > 4278190080 }
+func ge_4278190080_uint32(x uint32) bool { return x >= 4278190080 }
+func eq_4278190080_uint32(x uint32) bool { return x == 4278190080 }
+func ne_4278190080_uint32(x uint32) bool { return x != 4278190080 }
+func lt_4294967294_uint32(x uint32) bool { return x < 4294967294 }
+func le_4294967294_uint32(x uint32) bool { return x <= 4294967294 }
+func gt_4294967294_uint32(x uint32) bool { return x > 4294967294 }
+func ge_4294967294_uint32(x uint32) bool { return x >= 4294967294 }
+func eq_4294967294_uint32(x uint32) bool { return x == 4294967294 }
+func ne_4294967294_uint32(x uint32) bool { return x != 4294967294 }
+func lt_4294967295_uint32(x uint32) bool { return x < 4294967295 }
+func le_4294967295_uint32(x uint32) bool { return x <= 4294967295 }
+func gt_4294967295_uint32(x uint32) bool { return x > 4294967295 }
+func ge_4294967295_uint32(x uint32) bool { return x >= 4294967295 }
+func eq_4294967295_uint32(x uint32) bool { return x == 4294967295 }
+func ne_4294967295_uint32(x uint32) bool { return x != 4294967295 }
+
+var uint32_tests = []struct {
+ idx int // index of the constant used
+ exp result // expected results
+ fn func(uint32) bool
+}{
+ {idx: 0, exp: lt, fn: lt_0_uint32},
+ {idx: 0, exp: le, fn: le_0_uint32},
+ {idx: 0, exp: gt, fn: gt_0_uint32},
+ {idx: 0, exp: ge, fn: ge_0_uint32},
+ {idx: 0, exp: eq, fn: eq_0_uint32},
+ {idx: 0, exp: ne, fn: ne_0_uint32},
+ {idx: 1, exp: lt, fn: lt_1_uint32},
+ {idx: 1, exp: le, fn: le_1_uint32},
+ {idx: 1, exp: gt, fn: gt_1_uint32},
+ {idx: 1, exp: ge, fn: ge_1_uint32},
+ {idx: 1, exp: eq, fn: eq_1_uint32},
+ {idx: 1, exp: ne, fn: ne_1_uint32},
+ {idx: 2, exp: lt, fn: lt_126_uint32},
+ {idx: 2, exp: le, fn: le_126_uint32},
+ {idx: 2, exp: gt, fn: gt_126_uint32},
+ {idx: 2, exp: ge, fn: ge_126_uint32},
+ {idx: 2, exp: eq, fn: eq_126_uint32},
+ {idx: 2, exp: ne, fn: ne_126_uint32},
+ {idx: 3, exp: lt, fn: lt_127_uint32},
+ {idx: 3, exp: le, fn: le_127_uint32},
+ {idx: 3, exp: gt, fn: gt_127_uint32},
+ {idx: 3, exp: ge, fn: ge_127_uint32},
+ {idx: 3, exp: eq, fn: eq_127_uint32},
+ {idx: 3, exp: ne, fn: ne_127_uint32},
+ {idx: 4, exp: lt, fn: lt_128_uint32},
+ {idx: 4, exp: le, fn: le_128_uint32},
+ {idx: 4, exp: gt, fn: gt_128_uint32},
+ {idx: 4, exp: ge, fn: ge_128_uint32},
+ {idx: 4, exp: eq, fn: eq_128_uint32},
+ {idx: 4, exp: ne, fn: ne_128_uint32},
+ {idx: 5, exp: lt, fn: lt_254_uint32},
+ {idx: 5, exp: le, fn: le_254_uint32},
+ {idx: 5, exp: gt, fn: gt_254_uint32},
+ {idx: 5, exp: ge, fn: ge_254_uint32},
+ {idx: 5, exp: eq, fn: eq_254_uint32},
+ {idx: 5, exp: ne, fn: ne_254_uint32},
+ {idx: 6, exp: lt, fn: lt_255_uint32},
+ {idx: 6, exp: le, fn: le_255_uint32},
+ {idx: 6, exp: gt, fn: gt_255_uint32},
+ {idx: 6, exp: ge, fn: ge_255_uint32},
+ {idx: 6, exp: eq, fn: eq_255_uint32},
+ {idx: 6, exp: ne, fn: ne_255_uint32},
+ {idx: 7, exp: lt, fn: lt_256_uint32},
+ {idx: 7, exp: le, fn: le_256_uint32},
+ {idx: 7, exp: gt, fn: gt_256_uint32},
+ {idx: 7, exp: ge, fn: ge_256_uint32},
+ {idx: 7, exp: eq, fn: eq_256_uint32},
+ {idx: 7, exp: ne, fn: ne_256_uint32},
+ {idx: 8, exp: lt, fn: lt_32766_uint32},
+ {idx: 8, exp: le, fn: le_32766_uint32},
+ {idx: 8, exp: gt, fn: gt_32766_uint32},
+ {idx: 8, exp: ge, fn: ge_32766_uint32},
+ {idx: 8, exp: eq, fn: eq_32766_uint32},
+ {idx: 8, exp: ne, fn: ne_32766_uint32},
+ {idx: 9, exp: lt, fn: lt_32767_uint32},
+ {idx: 9, exp: le, fn: le_32767_uint32},
+ {idx: 9, exp: gt, fn: gt_32767_uint32},
+ {idx: 9, exp: ge, fn: ge_32767_uint32},
+ {idx: 9, exp: eq, fn: eq_32767_uint32},
+ {idx: 9, exp: ne, fn: ne_32767_uint32},
+ {idx: 10, exp: lt, fn: lt_32768_uint32},
+ {idx: 10, exp: le, fn: le_32768_uint32},
+ {idx: 10, exp: gt, fn: gt_32768_uint32},
+ {idx: 10, exp: ge, fn: ge_32768_uint32},
+ {idx: 10, exp: eq, fn: eq_32768_uint32},
+ {idx: 10, exp: ne, fn: ne_32768_uint32},
+ {idx: 11, exp: lt, fn: lt_65534_uint32},
+ {idx: 11, exp: le, fn: le_65534_uint32},
+ {idx: 11, exp: gt, fn: gt_65534_uint32},
+ {idx: 11, exp: ge, fn: ge_65534_uint32},
+ {idx: 11, exp: eq, fn: eq_65534_uint32},
+ {idx: 11, exp: ne, fn: ne_65534_uint32},
+ {idx: 12, exp: lt, fn: lt_65535_uint32},
+ {idx: 12, exp: le, fn: le_65535_uint32},
+ {idx: 12, exp: gt, fn: gt_65535_uint32},
+ {idx: 12, exp: ge, fn: ge_65535_uint32},
+ {idx: 12, exp: eq, fn: eq_65535_uint32},
+ {idx: 12, exp: ne, fn: ne_65535_uint32},
+ {idx: 13, exp: lt, fn: lt_65536_uint32},
+ {idx: 13, exp: le, fn: le_65536_uint32},
+ {idx: 13, exp: gt, fn: gt_65536_uint32},
+ {idx: 13, exp: ge, fn: ge_65536_uint32},
+ {idx: 13, exp: eq, fn: eq_65536_uint32},
+ {idx: 13, exp: ne, fn: ne_65536_uint32},
+ {idx: 14, exp: lt, fn: lt_2147483646_uint32},
+ {idx: 14, exp: le, fn: le_2147483646_uint32},
+ {idx: 14, exp: gt, fn: gt_2147483646_uint32},
+ {idx: 14, exp: ge, fn: ge_2147483646_uint32},
+ {idx: 14, exp: eq, fn: eq_2147483646_uint32},
+ {idx: 14, exp: ne, fn: ne_2147483646_uint32},
+ {idx: 15, exp: lt, fn: lt_2147483647_uint32},
+ {idx: 15, exp: le, fn: le_2147483647_uint32},
+ {idx: 15, exp: gt, fn: gt_2147483647_uint32},
+ {idx: 15, exp: ge, fn: ge_2147483647_uint32},
+ {idx: 15, exp: eq, fn: eq_2147483647_uint32},
+ {idx: 15, exp: ne, fn: ne_2147483647_uint32},
+ {idx: 16, exp: lt, fn: lt_2147483648_uint32},
+ {idx: 16, exp: le, fn: le_2147483648_uint32},
+ {idx: 16, exp: gt, fn: gt_2147483648_uint32},
+ {idx: 16, exp: ge, fn: ge_2147483648_uint32},
+ {idx: 16, exp: eq, fn: eq_2147483648_uint32},
+ {idx: 16, exp: ne, fn: ne_2147483648_uint32},
+ {idx: 17, exp: lt, fn: lt_4278190080_uint32},
+ {idx: 17, exp: le, fn: le_4278190080_uint32},
+ {idx: 17, exp: gt, fn: gt_4278190080_uint32},
+ {idx: 17, exp: ge, fn: ge_4278190080_uint32},
+ {idx: 17, exp: eq, fn: eq_4278190080_uint32},
+ {idx: 17, exp: ne, fn: ne_4278190080_uint32},
+ {idx: 18, exp: lt, fn: lt_4294967294_uint32},
+ {idx: 18, exp: le, fn: le_4294967294_uint32},
+ {idx: 18, exp: gt, fn: gt_4294967294_uint32},
+ {idx: 18, exp: ge, fn: ge_4294967294_uint32},
+ {idx: 18, exp: eq, fn: eq_4294967294_uint32},
+ {idx: 18, exp: ne, fn: ne_4294967294_uint32},
+ {idx: 19, exp: lt, fn: lt_4294967295_uint32},
+ {idx: 19, exp: le, fn: le_4294967295_uint32},
+ {idx: 19, exp: gt, fn: gt_4294967295_uint32},
+ {idx: 19, exp: ge, fn: ge_4294967295_uint32},
+ {idx: 19, exp: eq, fn: eq_4294967295_uint32},
+ {idx: 19, exp: ne, fn: ne_4294967295_uint32},
+}
+
+// uint16 tests
+var uint16_vals = []uint16{
+ 0,
+ 1,
+ 126,
+ 127,
+ 128,
+ 254,
+ 255,
+ 256,
+ 32766,
+ 32767,
+ 32768,
+ 65534,
+ 65535,
+}
+
+func lt_0_uint16(x uint16) bool { return x < 0 }
+func le_0_uint16(x uint16) bool { return x <= 0 }
+func gt_0_uint16(x uint16) bool { return x > 0 }
+func ge_0_uint16(x uint16) bool { return x >= 0 }
+func eq_0_uint16(x uint16) bool { return x == 0 }
+func ne_0_uint16(x uint16) bool { return x != 0 }
+func lt_1_uint16(x uint16) bool { return x < 1 }
+func le_1_uint16(x uint16) bool { return x <= 1 }
+func gt_1_uint16(x uint16) bool { return x > 1 }
+func ge_1_uint16(x uint16) bool { return x >= 1 }
+func eq_1_uint16(x uint16) bool { return x == 1 }
+func ne_1_uint16(x uint16) bool { return x != 1 }
+func lt_126_uint16(x uint16) bool { return x < 126 }
+func le_126_uint16(x uint16) bool { return x <= 126 }
+func gt_126_uint16(x uint16) bool { return x > 126 }
+func ge_126_uint16(x uint16) bool { return x >= 126 }
+func eq_126_uint16(x uint16) bool { return x == 126 }
+func ne_126_uint16(x uint16) bool { return x != 126 }
+func lt_127_uint16(x uint16) bool { return x < 127 }
+func le_127_uint16(x uint16) bool { return x <= 127 }
+func gt_127_uint16(x uint16) bool { return x > 127 }
+func ge_127_uint16(x uint16) bool { return x >= 127 }
+func eq_127_uint16(x uint16) bool { return x == 127 }
+func ne_127_uint16(x uint16) bool { return x != 127 }
+func lt_128_uint16(x uint16) bool { return x < 128 }
+func le_128_uint16(x uint16) bool { return x <= 128 }
+func gt_128_uint16(x uint16) bool { return x > 128 }
+func ge_128_uint16(x uint16) bool { return x >= 128 }
+func eq_128_uint16(x uint16) bool { return x == 128 }
+func ne_128_uint16(x uint16) bool { return x != 128 }
+func lt_254_uint16(x uint16) bool { return x < 254 }
+func le_254_uint16(x uint16) bool { return x <= 254 }
+func gt_254_uint16(x uint16) bool { return x > 254 }
+func ge_254_uint16(x uint16) bool { return x >= 254 }
+func eq_254_uint16(x uint16) bool { return x == 254 }
+func ne_254_uint16(x uint16) bool { return x != 254 }
+func lt_255_uint16(x uint16) bool { return x < 255 }
+func le_255_uint16(x uint16) bool { return x <= 255 }
+func gt_255_uint16(x uint16) bool { return x > 255 }
+func ge_255_uint16(x uint16) bool { return x >= 255 }
+func eq_255_uint16(x uint16) bool { return x == 255 }
+func ne_255_uint16(x uint16) bool { return x != 255 }
+func lt_256_uint16(x uint16) bool { return x < 256 }
+func le_256_uint16(x uint16) bool { return x <= 256 }
+func gt_256_uint16(x uint16) bool { return x > 256 }
+func ge_256_uint16(x uint16) bool { return x >= 256 }
+func eq_256_uint16(x uint16) bool { return x == 256 }
+func ne_256_uint16(x uint16) bool { return x != 256 }
+func lt_32766_uint16(x uint16) bool { return x < 32766 }
+func le_32766_uint16(x uint16) bool { return x <= 32766 }
+func gt_32766_uint16(x uint16) bool { return x > 32766 }
+func ge_32766_uint16(x uint16) bool { return x >= 32766 }
+func eq_32766_uint16(x uint16) bool { return x == 32766 }
+func ne_32766_uint16(x uint16) bool { return x != 32766 }
+func lt_32767_uint16(x uint16) bool { return x < 32767 }
+func le_32767_uint16(x uint16) bool { return x <= 32767 }
+func gt_32767_uint16(x uint16) bool { return x > 32767 }
+func ge_32767_uint16(x uint16) bool { return x >= 32767 }
+func eq_32767_uint16(x uint16) bool { return x == 32767 }
+func ne_32767_uint16(x uint16) bool { return x != 32767 }
+func lt_32768_uint16(x uint16) bool { return x < 32768 }
+func le_32768_uint16(x uint16) bool { return x <= 32768 }
+func gt_32768_uint16(x uint16) bool { return x > 32768 }
+func ge_32768_uint16(x uint16) bool { return x >= 32768 }
+func eq_32768_uint16(x uint16) bool { return x == 32768 }
+func ne_32768_uint16(x uint16) bool { return x != 32768 }
+func lt_65534_uint16(x uint16) bool { return x < 65534 }
+func le_65534_uint16(x uint16) bool { return x <= 65534 }
+func gt_65534_uint16(x uint16) bool { return x > 65534 }
+func ge_65534_uint16(x uint16) bool { return x >= 65534 }
+func eq_65534_uint16(x uint16) bool { return x == 65534 }
+func ne_65534_uint16(x uint16) bool { return x != 65534 }
+func lt_65535_uint16(x uint16) bool { return x < 65535 }
+func le_65535_uint16(x uint16) bool { return x <= 65535 }
+func gt_65535_uint16(x uint16) bool { return x > 65535 }
+func ge_65535_uint16(x uint16) bool { return x >= 65535 }
+func eq_65535_uint16(x uint16) bool { return x == 65535 }
+func ne_65535_uint16(x uint16) bool { return x != 65535 }
+
+var uint16_tests = []struct {
+ idx int // index of the constant used
+ exp result // expected results
+ fn func(uint16) bool
+}{
+ {idx: 0, exp: lt, fn: lt_0_uint16},
+ {idx: 0, exp: le, fn: le_0_uint16},
+ {idx: 0, exp: gt, fn: gt_0_uint16},
+ {idx: 0, exp: ge, fn: ge_0_uint16},
+ {idx: 0, exp: eq, fn: eq_0_uint16},
+ {idx: 0, exp: ne, fn: ne_0_uint16},
+ {idx: 1, exp: lt, fn: lt_1_uint16},
+ {idx: 1, exp: le, fn: le_1_uint16},
+ {idx: 1, exp: gt, fn: gt_1_uint16},
+ {idx: 1, exp: ge, fn: ge_1_uint16},
+ {idx: 1, exp: eq, fn: eq_1_uint16},
+ {idx: 1, exp: ne, fn: ne_1_uint16},
+ {idx: 2, exp: lt, fn: lt_126_uint16},
+ {idx: 2, exp: le, fn: le_126_uint16},
+ {idx: 2, exp: gt, fn: gt_126_uint16},
+ {idx: 2, exp: ge, fn: ge_126_uint16},
+ {idx: 2, exp: eq, fn: eq_126_uint16},
+ {idx: 2, exp: ne, fn: ne_126_uint16},
+ {idx: 3, exp: lt, fn: lt_127_uint16},
+ {idx: 3, exp: le, fn: le_127_uint16},
+ {idx: 3, exp: gt, fn: gt_127_uint16},
+ {idx: 3, exp: ge, fn: ge_127_uint16},
+ {idx: 3, exp: eq, fn: eq_127_uint16},
+ {idx: 3, exp: ne, fn: ne_127_uint16},
+ {idx: 4, exp: lt, fn: lt_128_uint16},
+ {idx: 4, exp: le, fn: le_128_uint16},
+ {idx: 4, exp: gt, fn: gt_128_uint16},
+ {idx: 4, exp: ge, fn: ge_128_uint16},
+ {idx: 4, exp: eq, fn: eq_128_uint16},
+ {idx: 4, exp: ne, fn: ne_128_uint16},
+ {idx: 5, exp: lt, fn: lt_254_uint16},
+ {idx: 5, exp: le, fn: le_254_uint16},
+ {idx: 5, exp: gt, fn: gt_254_uint16},
+ {idx: 5, exp: ge, fn: ge_254_uint16},
+ {idx: 5, exp: eq, fn: eq_254_uint16},
+ {idx: 5, exp: ne, fn: ne_254_uint16},
+ {idx: 6, exp: lt, fn: lt_255_uint16},
+ {idx: 6, exp: le, fn: le_255_uint16},
+ {idx: 6, exp: gt, fn: gt_255_uint16},
+ {idx: 6, exp: ge, fn: ge_255_uint16},
+ {idx: 6, exp: eq, fn: eq_255_uint16},
+ {idx: 6, exp: ne, fn: ne_255_uint16},
+ {idx: 7, exp: lt, fn: lt_256_uint16},
+ {idx: 7, exp: le, fn: le_256_uint16},
+ {idx: 7, exp: gt, fn: gt_256_uint16},
+ {idx: 7, exp: ge, fn: ge_256_uint16},
+ {idx: 7, exp: eq, fn: eq_256_uint16},
+ {idx: 7, exp: ne, fn: ne_256_uint16},
+ {idx: 8, exp: lt, fn: lt_32766_uint16},
+ {idx: 8, exp: le, fn: le_32766_uint16},
+ {idx: 8, exp: gt, fn: gt_32766_uint16},
+ {idx: 8, exp: ge, fn: ge_32766_uint16},
+ {idx: 8, exp: eq, fn: eq_32766_uint16},
+ {idx: 8, exp: ne, fn: ne_32766_uint16},
+ {idx: 9, exp: lt, fn: lt_32767_uint16},
+ {idx: 9, exp: le, fn: le_32767_uint16},
+ {idx: 9, exp: gt, fn: gt_32767_uint16},
+ {idx: 9, exp: ge, fn: ge_32767_uint16},
+ {idx: 9, exp: eq, fn: eq_32767_uint16},
+ {idx: 9, exp: ne, fn: ne_32767_uint16},
+ {idx: 10, exp: lt, fn: lt_32768_uint16},
+ {idx: 10, exp: le, fn: le_32768_uint16},
+ {idx: 10, exp: gt, fn: gt_32768_uint16},
+ {idx: 10, exp: ge, fn: ge_32768_uint16},
+ {idx: 10, exp: eq, fn: eq_32768_uint16},
+ {idx: 10, exp: ne, fn: ne_32768_uint16},
+ {idx: 11, exp: lt, fn: lt_65534_uint16},
+ {idx: 11, exp: le, fn: le_65534_uint16},
+ {idx: 11, exp: gt, fn: gt_65534_uint16},
+ {idx: 11, exp: ge, fn: ge_65534_uint16},
+ {idx: 11, exp: eq, fn: eq_65534_uint16},
+ {idx: 11, exp: ne, fn: ne_65534_uint16},
+ {idx: 12, exp: lt, fn: lt_65535_uint16},
+ {idx: 12, exp: le, fn: le_65535_uint16},
+ {idx: 12, exp: gt, fn: gt_65535_uint16},
+ {idx: 12, exp: ge, fn: ge_65535_uint16},
+ {idx: 12, exp: eq, fn: eq_65535_uint16},
+ {idx: 12, exp: ne, fn: ne_65535_uint16},
+}
+
+// uint8 tests
+var uint8_vals = []uint8{
+ 0,
+ 1,
+ 126,
+ 127,
+ 128,
+ 254,
+ 255,
+}
+
+func lt_0_uint8(x uint8) bool { return x < 0 }
+func le_0_uint8(x uint8) bool { return x <= 0 }
+func gt_0_uint8(x uint8) bool { return x > 0 }
+func ge_0_uint8(x uint8) bool { return x >= 0 }
+func eq_0_uint8(x uint8) bool { return x == 0 }
+func ne_0_uint8(x uint8) bool { return x != 0 }
+func lt_1_uint8(x uint8) bool { return x < 1 }
+func le_1_uint8(x uint8) bool { return x <= 1 }
+func gt_1_uint8(x uint8) bool { return x > 1 }
+func ge_1_uint8(x uint8) bool { return x >= 1 }
+func eq_1_uint8(x uint8) bool { return x == 1 }
+func ne_1_uint8(x uint8) bool { return x != 1 }
+func lt_126_uint8(x uint8) bool { return x < 126 }
+func le_126_uint8(x uint8) bool { return x <= 126 }
+func gt_126_uint8(x uint8) bool { return x > 126 }
+func ge_126_uint8(x uint8) bool { return x >= 126 }
+func eq_126_uint8(x uint8) bool { return x == 126 }
+func ne_126_uint8(x uint8) bool { return x != 126 }
+func lt_127_uint8(x uint8) bool { return x < 127 }
+func le_127_uint8(x uint8) bool { return x <= 127 }
+func gt_127_uint8(x uint8) bool { return x > 127 }
+func ge_127_uint8(x uint8) bool { return x >= 127 }
+func eq_127_uint8(x uint8) bool { return x == 127 }
+func ne_127_uint8(x uint8) bool { return x != 127 }
+func lt_128_uint8(x uint8) bool { return x < 128 }
+func le_128_uint8(x uint8) bool { return x <= 128 }
+func gt_128_uint8(x uint8) bool { return x > 128 }
+func ge_128_uint8(x uint8) bool { return x >= 128 }
+func eq_128_uint8(x uint8) bool { return x == 128 }
+func ne_128_uint8(x uint8) bool { return x != 128 }
+func lt_254_uint8(x uint8) bool { return x < 254 }
+func le_254_uint8(x uint8) bool { return x <= 254 }
+func gt_254_uint8(x uint8) bool { return x > 254 }
+func ge_254_uint8(x uint8) bool { return x >= 254 }
+func eq_254_uint8(x uint8) bool { return x == 254 }
+func ne_254_uint8(x uint8) bool { return x != 254 }
+func lt_255_uint8(x uint8) bool { return x < 255 }
+func le_255_uint8(x uint8) bool { return x <= 255 }
+func gt_255_uint8(x uint8) bool { return x > 255 }
+func ge_255_uint8(x uint8) bool { return x >= 255 }
+func eq_255_uint8(x uint8) bool { return x == 255 }
+func ne_255_uint8(x uint8) bool { return x != 255 }
+
+var uint8_tests = []struct {
+ idx int // index of the constant used
+ exp result // expected results
+ fn func(uint8) bool
+}{
+ {idx: 0, exp: lt, fn: lt_0_uint8},
+ {idx: 0, exp: le, fn: le_0_uint8},
+ {idx: 0, exp: gt, fn: gt_0_uint8},
+ {idx: 0, exp: ge, fn: ge_0_uint8},
+ {idx: 0, exp: eq, fn: eq_0_uint8},
+ {idx: 0, exp: ne, fn: ne_0_uint8},
+ {idx: 1, exp: lt, fn: lt_1_uint8},
+ {idx: 1, exp: le, fn: le_1_uint8},
+ {idx: 1, exp: gt, fn: gt_1_uint8},
+ {idx: 1, exp: ge, fn: ge_1_uint8},
+ {idx: 1, exp: eq, fn: eq_1_uint8},
+ {idx: 1, exp: ne, fn: ne_1_uint8},
+ {idx: 2, exp: lt, fn: lt_126_uint8},
+ {idx: 2, exp: le, fn: le_126_uint8},
+ {idx: 2, exp: gt, fn: gt_126_uint8},
+ {idx: 2, exp: ge, fn: ge_126_uint8},
+ {idx: 2, exp: eq, fn: eq_126_uint8},
+ {idx: 2, exp: ne, fn: ne_126_uint8},
+ {idx: 3, exp: lt, fn: lt_127_uint8},
+ {idx: 3, exp: le, fn: le_127_uint8},
+ {idx: 3, exp: gt, fn: gt_127_uint8},
+ {idx: 3, exp: ge, fn: ge_127_uint8},
+ {idx: 3, exp: eq, fn: eq_127_uint8},
+ {idx: 3, exp: ne, fn: ne_127_uint8},
+ {idx: 4, exp: lt, fn: lt_128_uint8},
+ {idx: 4, exp: le, fn: le_128_uint8},
+ {idx: 4, exp: gt, fn: gt_128_uint8},
+ {idx: 4, exp: ge, fn: ge_128_uint8},
+ {idx: 4, exp: eq, fn: eq_128_uint8},
+ {idx: 4, exp: ne, fn: ne_128_uint8},
+ {idx: 5, exp: lt, fn: lt_254_uint8},
+ {idx: 5, exp: le, fn: le_254_uint8},
+ {idx: 5, exp: gt, fn: gt_254_uint8},
+ {idx: 5, exp: ge, fn: ge_254_uint8},
+ {idx: 5, exp: eq, fn: eq_254_uint8},
+ {idx: 5, exp: ne, fn: ne_254_uint8},
+ {idx: 6, exp: lt, fn: lt_255_uint8},
+ {idx: 6, exp: le, fn: le_255_uint8},
+ {idx: 6, exp: gt, fn: gt_255_uint8},
+ {idx: 6, exp: ge, fn: ge_255_uint8},
+ {idx: 6, exp: eq, fn: eq_255_uint8},
+ {idx: 6, exp: ne, fn: ne_255_uint8},
+}
+
+// int64 tests
+var int64_vals = []int64{
+ -9223372036854775808,
+ -9223372036854775807,
+ -2147483649,
+ -2147483648,
+ -2147483647,
+ -32769,
+ -32768,
+ -32767,
+ -129,
+ -128,
+ -127,
+ -1,
+ 0,
+ 1,
+ 126,
+ 127,
+ 128,
+ 254,
+ 255,
+ 256,
+ 32766,
+ 32767,
+ 32768,
+ 65534,
+ 65535,
+ 65536,
+ 2147483646,
+ 2147483647,
+ 2147483648,
+ 4278190080,
+ 4294967294,
+ 4294967295,
+ 4294967296,
+ 1095216660480,
+ 9223372036854775806,
+ 9223372036854775807,
+}
+
+func lt_neg9223372036854775808_int64(x int64) bool { return x < -9223372036854775808 }
+func le_neg9223372036854775808_int64(x int64) bool { return x <= -9223372036854775808 }
+func gt_neg9223372036854775808_int64(x int64) bool { return x > -9223372036854775808 }
+func ge_neg9223372036854775808_int64(x int64) bool { return x >= -9223372036854775808 }
+func eq_neg9223372036854775808_int64(x int64) bool { return x == -9223372036854775808 }
+func ne_neg9223372036854775808_int64(x int64) bool { return x != -9223372036854775808 }
+func lt_neg9223372036854775807_int64(x int64) bool { return x < -9223372036854775807 }
+func le_neg9223372036854775807_int64(x int64) bool { return x <= -9223372036854775807 }
+func gt_neg9223372036854775807_int64(x int64) bool { return x > -9223372036854775807 }
+func ge_neg9223372036854775807_int64(x int64) bool { return x >= -9223372036854775807 }
+func eq_neg9223372036854775807_int64(x int64) bool { return x == -9223372036854775807 }
+func ne_neg9223372036854775807_int64(x int64) bool { return x != -9223372036854775807 }
+func lt_neg2147483649_int64(x int64) bool { return x < -2147483649 }
+func le_neg2147483649_int64(x int64) bool { return x <= -2147483649 }
+func gt_neg2147483649_int64(x int64) bool { return x > -2147483649 }
+func ge_neg2147483649_int64(x int64) bool { return x >= -2147483649 }
+func eq_neg2147483649_int64(x int64) bool { return x == -2147483649 }
+func ne_neg2147483649_int64(x int64) bool { return x != -2147483649 }
+func lt_neg2147483648_int64(x int64) bool { return x < -2147483648 }
+func le_neg2147483648_int64(x int64) bool { return x <= -2147483648 }
+func gt_neg2147483648_int64(x int64) bool { return x > -2147483648 }
+func ge_neg2147483648_int64(x int64) bool { return x >= -2147483648 }
+func eq_neg2147483648_int64(x int64) bool { return x == -2147483648 }
+func ne_neg2147483648_int64(x int64) bool { return x != -2147483648 }
+func lt_neg2147483647_int64(x int64) bool { return x < -2147483647 }
+func le_neg2147483647_int64(x int64) bool { return x <= -2147483647 }
+func gt_neg2147483647_int64(x int64) bool { return x > -2147483647 }
+func ge_neg2147483647_int64(x int64) bool { return x >= -2147483647 }
+func eq_neg2147483647_int64(x int64) bool { return x == -2147483647 }
+func ne_neg2147483647_int64(x int64) bool { return x != -2147483647 }
+func lt_neg32769_int64(x int64) bool { return x < -32769 }
+func le_neg32769_int64(x int64) bool { return x <= -32769 }
+func gt_neg32769_int64(x int64) bool { return x > -32769 }
+func ge_neg32769_int64(x int64) bool { return x >= -32769 }
+func eq_neg32769_int64(x int64) bool { return x == -32769 }
+func ne_neg32769_int64(x int64) bool { return x != -32769 }
+func lt_neg32768_int64(x int64) bool { return x < -32768 }
+func le_neg32768_int64(x int64) bool { return x <= -32768 }
+func gt_neg32768_int64(x int64) bool { return x > -32768 }
+func ge_neg32768_int64(x int64) bool { return x >= -32768 }
+func eq_neg32768_int64(x int64) bool { return x == -32768 }
+func ne_neg32768_int64(x int64) bool { return x != -32768 }
+func lt_neg32767_int64(x int64) bool { return x < -32767 }
+func le_neg32767_int64(x int64) bool { return x <= -32767 }
+func gt_neg32767_int64(x int64) bool { return x > -32767 }
+func ge_neg32767_int64(x int64) bool { return x >= -32767 }
+func eq_neg32767_int64(x int64) bool { return x == -32767 }
+func ne_neg32767_int64(x int64) bool { return x != -32767 }
+func lt_neg129_int64(x int64) bool { return x < -129 }
+func le_neg129_int64(x int64) bool { return x <= -129 }
+func gt_neg129_int64(x int64) bool { return x > -129 }
+func ge_neg129_int64(x int64) bool { return x >= -129 }
+func eq_neg129_int64(x int64) bool { return x == -129 }
+func ne_neg129_int64(x int64) bool { return x != -129 }
+func lt_neg128_int64(x int64) bool { return x < -128 }
+func le_neg128_int64(x int64) bool { return x <= -128 }
+func gt_neg128_int64(x int64) bool { return x > -128 }
+func ge_neg128_int64(x int64) bool { return x >= -128 }
+func eq_neg128_int64(x int64) bool { return x == -128 }
+func ne_neg128_int64(x int64) bool { return x != -128 }
+func lt_neg127_int64(x int64) bool { return x < -127 }
+func le_neg127_int64(x int64) bool { return x <= -127 }
+func gt_neg127_int64(x int64) bool { return x > -127 }
+func ge_neg127_int64(x int64) bool { return x >= -127 }
+func eq_neg127_int64(x int64) bool { return x == -127 }
+func ne_neg127_int64(x int64) bool { return x != -127 }
+func lt_neg1_int64(x int64) bool { return x < -1 }
+func le_neg1_int64(x int64) bool { return x <= -1 }
+func gt_neg1_int64(x int64) bool { return x > -1 }
+func ge_neg1_int64(x int64) bool { return x >= -1 }
+func eq_neg1_int64(x int64) bool { return x == -1 }
+func ne_neg1_int64(x int64) bool { return x != -1 }
+func lt_0_int64(x int64) bool { return x < 0 }
+func le_0_int64(x int64) bool { return x <= 0 }
+func gt_0_int64(x int64) bool { return x > 0 }
+func ge_0_int64(x int64) bool { return x >= 0 }
+func eq_0_int64(x int64) bool { return x == 0 }
+func ne_0_int64(x int64) bool { return x != 0 }
+func lt_1_int64(x int64) bool { return x < 1 }
+func le_1_int64(x int64) bool { return x <= 1 }
+func gt_1_int64(x int64) bool { return x > 1 }
+func ge_1_int64(x int64) bool { return x >= 1 }
+func eq_1_int64(x int64) bool { return x == 1 }
+func ne_1_int64(x int64) bool { return x != 1 }
+func lt_126_int64(x int64) bool { return x < 126 }
+func le_126_int64(x int64) bool { return x <= 126 }
+func gt_126_int64(x int64) bool { return x > 126 }
+func ge_126_int64(x int64) bool { return x >= 126 }
+func eq_126_int64(x int64) bool { return x == 126 }
+func ne_126_int64(x int64) bool { return x != 126 }
+func lt_127_int64(x int64) bool { return x < 127 }
+func le_127_int64(x int64) bool { return x <= 127 }
+func gt_127_int64(x int64) bool { return x > 127 }
+func ge_127_int64(x int64) bool { return x >= 127 }
+func eq_127_int64(x int64) bool { return x == 127 }
+func ne_127_int64(x int64) bool { return x != 127 }
+func lt_128_int64(x int64) bool { return x < 128 }
+func le_128_int64(x int64) bool { return x <= 128 }
+func gt_128_int64(x int64) bool { return x > 128 }
+func ge_128_int64(x int64) bool { return x >= 128 }
+func eq_128_int64(x int64) bool { return x == 128 }
+func ne_128_int64(x int64) bool { return x != 128 }
+func lt_254_int64(x int64) bool { return x < 254 }
+func le_254_int64(x int64) bool { return x <= 254 }
+func gt_254_int64(x int64) bool { return x > 254 }
+func ge_254_int64(x int64) bool { return x >= 254 }
+func eq_254_int64(x int64) bool { return x == 254 }
+func ne_254_int64(x int64) bool { return x != 254 }
+func lt_255_int64(x int64) bool { return x < 255 }
+func le_255_int64(x int64) bool { return x <= 255 }
+func gt_255_int64(x int64) bool { return x > 255 }
+func ge_255_int64(x int64) bool { return x >= 255 }
+func eq_255_int64(x int64) bool { return x == 255 }
+func ne_255_int64(x int64) bool { return x != 255 }
+func lt_256_int64(x int64) bool { return x < 256 }
+func le_256_int64(x int64) bool { return x <= 256 }
+func gt_256_int64(x int64) bool { return x > 256 }
+func ge_256_int64(x int64) bool { return x >= 256 }
+func eq_256_int64(x int64) bool { return x == 256 }
+func ne_256_int64(x int64) bool { return x != 256 }
+func lt_32766_int64(x int64) bool { return x < 32766 }
+func le_32766_int64(x int64) bool { return x <= 32766 }
+func gt_32766_int64(x int64) bool { return x > 32766 }
+func ge_32766_int64(x int64) bool { return x >= 32766 }
+func eq_32766_int64(x int64) bool { return x == 32766 }
+func ne_32766_int64(x int64) bool { return x != 32766 }
+func lt_32767_int64(x int64) bool { return x < 32767 }
+func le_32767_int64(x int64) bool { return x <= 32767 }
+func gt_32767_int64(x int64) bool { return x > 32767 }
+func ge_32767_int64(x int64) bool { return x >= 32767 }
+func eq_32767_int64(x int64) bool { return x == 32767 }
+func ne_32767_int64(x int64) bool { return x != 32767 }
+func lt_32768_int64(x int64) bool { return x < 32768 }
+func le_32768_int64(x int64) bool { return x <= 32768 }
+func gt_32768_int64(x int64) bool { return x > 32768 }
+func ge_32768_int64(x int64) bool { return x >= 32768 }
+func eq_32768_int64(x int64) bool { return x == 32768 }
+func ne_32768_int64(x int64) bool { return x != 32768 }
+func lt_65534_int64(x int64) bool { return x < 65534 }
+func le_65534_int64(x int64) bool { return x <= 65534 }
+func gt_65534_int64(x int64) bool { return x > 65534 }
+func ge_65534_int64(x int64) bool { return x >= 65534 }
+func eq_65534_int64(x int64) bool { return x == 65534 }
+func ne_65534_int64(x int64) bool { return x != 65534 }
+func lt_65535_int64(x int64) bool { return x < 65535 }
+func le_65535_int64(x int64) bool { return x <= 65535 }
+func gt_65535_int64(x int64) bool { return x > 65535 }
+func ge_65535_int64(x int64) bool { return x >= 65535 }
+func eq_65535_int64(x int64) bool { return x == 65535 }
+func ne_65535_int64(x int64) bool { return x != 65535 }
+func lt_65536_int64(x int64) bool { return x < 65536 }
+func le_65536_int64(x int64) bool { return x <= 65536 }
+func gt_65536_int64(x int64) bool { return x > 65536 }
+func ge_65536_int64(x int64) bool { return x >= 65536 }
+func eq_65536_int64(x int64) bool { return x == 65536 }
+func ne_65536_int64(x int64) bool { return x != 65536 }
+func lt_2147483646_int64(x int64) bool { return x < 2147483646 }
+func le_2147483646_int64(x int64) bool { return x <= 2147483646 }
+func gt_2147483646_int64(x int64) bool { return x > 2147483646 }
+func ge_2147483646_int64(x int64) bool { return x >= 2147483646 }
+func eq_2147483646_int64(x int64) bool { return x == 2147483646 }
+func ne_2147483646_int64(x int64) bool { return x != 2147483646 }
+func lt_2147483647_int64(x int64) bool { return x < 2147483647 }
+func le_2147483647_int64(x int64) bool { return x <= 2147483647 }
+func gt_2147483647_int64(x int64) bool { return x > 2147483647 }
+func ge_2147483647_int64(x int64) bool { return x >= 2147483647 }
+func eq_2147483647_int64(x int64) bool { return x == 2147483647 }
+func ne_2147483647_int64(x int64) bool { return x != 2147483647 }
+func lt_2147483648_int64(x int64) bool { return x < 2147483648 }
+func le_2147483648_int64(x int64) bool { return x <= 2147483648 }
+func gt_2147483648_int64(x int64) bool { return x > 2147483648 }
+func ge_2147483648_int64(x int64) bool { return x >= 2147483648 }
+func eq_2147483648_int64(x int64) bool { return x == 2147483648 }
+func ne_2147483648_int64(x int64) bool { return x != 2147483648 }
+func lt_4278190080_int64(x int64) bool { return x < 4278190080 }
+func le_4278190080_int64(x int64) bool { return x <= 4278190080 }
+func gt_4278190080_int64(x int64) bool { return x > 4278190080 }
+func ge_4278190080_int64(x int64) bool { return x >= 4278190080 }
+func eq_4278190080_int64(x int64) bool { return x == 4278190080 }
+func ne_4278190080_int64(x int64) bool { return x != 4278190080 }
+func lt_4294967294_int64(x int64) bool { return x < 4294967294 }
+func le_4294967294_int64(x int64) bool { return x <= 4294967294 }
+func gt_4294967294_int64(x int64) bool { return x > 4294967294 }
+func ge_4294967294_int64(x int64) bool { return x >= 4294967294 }
+func eq_4294967294_int64(x int64) bool { return x == 4294967294 }
+func ne_4294967294_int64(x int64) bool { return x != 4294967294 }
+func lt_4294967295_int64(x int64) bool { return x < 4294967295 }
+func le_4294967295_int64(x int64) bool { return x <= 4294967295 }
+func gt_4294967295_int64(x int64) bool { return x > 4294967295 }
+func ge_4294967295_int64(x int64) bool { return x >= 4294967295 }
+func eq_4294967295_int64(x int64) bool { return x == 4294967295 }
+func ne_4294967295_int64(x int64) bool { return x != 4294967295 }
+func lt_4294967296_int64(x int64) bool { return x < 4294967296 }
+func le_4294967296_int64(x int64) bool { return x <= 4294967296 }
+func gt_4294967296_int64(x int64) bool { return x > 4294967296 }
+func ge_4294967296_int64(x int64) bool { return x >= 4294967296 }
+func eq_4294967296_int64(x int64) bool { return x == 4294967296 }
+func ne_4294967296_int64(x int64) bool { return x != 4294967296 }
+func lt_1095216660480_int64(x int64) bool { return x < 1095216660480 }
+func le_1095216660480_int64(x int64) bool { return x <= 1095216660480 }
+func gt_1095216660480_int64(x int64) bool { return x > 1095216660480 }
+func ge_1095216660480_int64(x int64) bool { return x >= 1095216660480 }
+func eq_1095216660480_int64(x int64) bool { return x == 1095216660480 }
+func ne_1095216660480_int64(x int64) bool { return x != 1095216660480 }
+func lt_9223372036854775806_int64(x int64) bool { return x < 9223372036854775806 }
+func le_9223372036854775806_int64(x int64) bool { return x <= 9223372036854775806 }
+func gt_9223372036854775806_int64(x int64) bool { return x > 9223372036854775806 }
+func ge_9223372036854775806_int64(x int64) bool { return x >= 9223372036854775806 }
+func eq_9223372036854775806_int64(x int64) bool { return x == 9223372036854775806 }
+func ne_9223372036854775806_int64(x int64) bool { return x != 9223372036854775806 }
+func lt_9223372036854775807_int64(x int64) bool { return x < 9223372036854775807 }
+func le_9223372036854775807_int64(x int64) bool { return x <= 9223372036854775807 }
+func gt_9223372036854775807_int64(x int64) bool { return x > 9223372036854775807 }
+func ge_9223372036854775807_int64(x int64) bool { return x >= 9223372036854775807 }
+func eq_9223372036854775807_int64(x int64) bool { return x == 9223372036854775807 }
+func ne_9223372036854775807_int64(x int64) bool { return x != 9223372036854775807 }
+
+var int64_tests = []struct {
+ idx int // index of the constant used
+ exp result // expected results
+ fn func(int64) bool
+}{
+ {idx: 0, exp: lt, fn: lt_neg9223372036854775808_int64},
+ {idx: 0, exp: le, fn: le_neg9223372036854775808_int64},
+ {idx: 0, exp: gt, fn: gt_neg9223372036854775808_int64},
+ {idx: 0, exp: ge, fn: ge_neg9223372036854775808_int64},
+ {idx: 0, exp: eq, fn: eq_neg9223372036854775808_int64},
+ {idx: 0, exp: ne, fn: ne_neg9223372036854775808_int64},
+ {idx: 1, exp: lt, fn: lt_neg9223372036854775807_int64},
+ {idx: 1, exp: le, fn: le_neg9223372036854775807_int64},
+ {idx: 1, exp: gt, fn: gt_neg9223372036854775807_int64},
+ {idx: 1, exp: ge, fn: ge_neg9223372036854775807_int64},
+ {idx: 1, exp: eq, fn: eq_neg9223372036854775807_int64},
+ {idx: 1, exp: ne, fn: ne_neg9223372036854775807_int64},
+ {idx: 2, exp: lt, fn: lt_neg2147483649_int64},
+ {idx: 2, exp: le, fn: le_neg2147483649_int64},
+ {idx: 2, exp: gt, fn: gt_neg2147483649_int64},
+ {idx: 2, exp: ge, fn: ge_neg2147483649_int64},
+ {idx: 2, exp: eq, fn: eq_neg2147483649_int64},
+ {idx: 2, exp: ne, fn: ne_neg2147483649_int64},
+ {idx: 3, exp: lt, fn: lt_neg2147483648_int64},
+ {idx: 3, exp: le, fn: le_neg2147483648_int64},
+ {idx: 3, exp: gt, fn: gt_neg2147483648_int64},
+ {idx: 3, exp: ge, fn: ge_neg2147483648_int64},
+ {idx: 3, exp: eq, fn: eq_neg2147483648_int64},
+ {idx: 3, exp: ne, fn: ne_neg2147483648_int64},
+ {idx: 4, exp: lt, fn: lt_neg2147483647_int64},
+ {idx: 4, exp: le, fn: le_neg2147483647_int64},
+ {idx: 4, exp: gt, fn: gt_neg2147483647_int64},
+ {idx: 4, exp: ge, fn: ge_neg2147483647_int64},
+ {idx: 4, exp: eq, fn: eq_neg2147483647_int64},
+ {idx: 4, exp: ne, fn: ne_neg2147483647_int64},
+ {idx: 5, exp: lt, fn: lt_neg32769_int64},
+ {idx: 5, exp: le, fn: le_neg32769_int64},
+ {idx: 5, exp: gt, fn: gt_neg32769_int64},
+ {idx: 5, exp: ge, fn: ge_neg32769_int64},
+ {idx: 5, exp: eq, fn: eq_neg32769_int64},
+ {idx: 5, exp: ne, fn: ne_neg32769_int64},
+ {idx: 6, exp: lt, fn: lt_neg32768_int64},
+ {idx: 6, exp: le, fn: le_neg32768_int64},
+ {idx: 6, exp: gt, fn: gt_neg32768_int64},
+ {idx: 6, exp: ge, fn: ge_neg32768_int64},
+ {idx: 6, exp: eq, fn: eq_neg32768_int64},
+ {idx: 6, exp: ne, fn: ne_neg32768_int64},
+ {idx: 7, exp: lt, fn: lt_neg32767_int64},
+ {idx: 7, exp: le, fn: le_neg32767_int64},
+ {idx: 7, exp: gt, fn: gt_neg32767_int64},
+ {idx: 7, exp: ge, fn: ge_neg32767_int64},
+ {idx: 7, exp: eq, fn: eq_neg32767_int64},
+ {idx: 7, exp: ne, fn: ne_neg32767_int64},
+ {idx: 8, exp: lt, fn: lt_neg129_int64},
+ {idx: 8, exp: le, fn: le_neg129_int64},
+ {idx: 8, exp: gt, fn: gt_neg129_int64},
+ {idx: 8, exp: ge, fn: ge_neg129_int64},
+ {idx: 8, exp: eq, fn: eq_neg129_int64},
+ {idx: 8, exp: ne, fn: ne_neg129_int64},
+ {idx: 9, exp: lt, fn: lt_neg128_int64},
+ {idx: 9, exp: le, fn: le_neg128_int64},
+ {idx: 9, exp: gt, fn: gt_neg128_int64},
+ {idx: 9, exp: ge, fn: ge_neg128_int64},
+ {idx: 9, exp: eq, fn: eq_neg128_int64},
+ {idx: 9, exp: ne, fn: ne_neg128_int64},
+ {idx: 10, exp: lt, fn: lt_neg127_int64},
+ {idx: 10, exp: le, fn: le_neg127_int64},
+ {idx: 10, exp: gt, fn: gt_neg127_int64},
+ {idx: 10, exp: ge, fn: ge_neg127_int64},
+ {idx: 10, exp: eq, fn: eq_neg127_int64},
+ {idx: 10, exp: ne, fn: ne_neg127_int64},
+ {idx: 11, exp: lt, fn: lt_neg1_int64},
+ {idx: 11, exp: le, fn: le_neg1_int64},
+ {idx: 11, exp: gt, fn: gt_neg1_int64},
+ {idx: 11, exp: ge, fn: ge_neg1_int64},
+ {idx: 11, exp: eq, fn: eq_neg1_int64},
+ {idx: 11, exp: ne, fn: ne_neg1_int64},
+ {idx: 12, exp: lt, fn: lt_0_int64},
+ {idx: 12, exp: le, fn: le_0_int64},
+ {idx: 12, exp: gt, fn: gt_0_int64},
+ {idx: 12, exp: ge, fn: ge_0_int64},
+ {idx: 12, exp: eq, fn: eq_0_int64},
+ {idx: 12, exp: ne, fn: ne_0_int64},
+ {idx: 13, exp: lt, fn: lt_1_int64},
+ {idx: 13, exp: le, fn: le_1_int64},
+ {idx: 13, exp: gt, fn: gt_1_int64},
+ {idx: 13, exp: ge, fn: ge_1_int64},
+ {idx: 13, exp: eq, fn: eq_1_int64},
+ {idx: 13, exp: ne, fn: ne_1_int64},
+ {idx: 14, exp: lt, fn: lt_126_int64},
+ {idx: 14, exp: le, fn: le_126_int64},
+ {idx: 14, exp: gt, fn: gt_126_int64},
+ {idx: 14, exp: ge, fn: ge_126_int64},
+ {idx: 14, exp: eq, fn: eq_126_int64},
+ {idx: 14, exp: ne, fn: ne_126_int64},
+ {idx: 15, exp: lt, fn: lt_127_int64},
+ {idx: 15, exp: le, fn: le_127_int64},
+ {idx: 15, exp: gt, fn: gt_127_int64},
+ {idx: 15, exp: ge, fn: ge_127_int64},
+ {idx: 15, exp: eq, fn: eq_127_int64},
+ {idx: 15, exp: ne, fn: ne_127_int64},
+ {idx: 16, exp: lt, fn: lt_128_int64},
+ {idx: 16, exp: le, fn: le_128_int64},
+ {idx: 16, exp: gt, fn: gt_128_int64},
+ {idx: 16, exp: ge, fn: ge_128_int64},
+ {idx: 16, exp: eq, fn: eq_128_int64},
+ {idx: 16, exp: ne, fn: ne_128_int64},
+ {idx: 17, exp: lt, fn: lt_254_int64},
+ {idx: 17, exp: le, fn: le_254_int64},
+ {idx: 17, exp: gt, fn: gt_254_int64},
+ {idx: 17, exp: ge, fn: ge_254_int64},
+ {idx: 17, exp: eq, fn: eq_254_int64},
+ {idx: 17, exp: ne, fn: ne_254_int64},
+ {idx: 18, exp: lt, fn: lt_255_int64},
+ {idx: 18, exp: le, fn: le_255_int64},
+ {idx: 18, exp: gt, fn: gt_255_int64},
+ {idx: 18, exp: ge, fn: ge_255_int64},
+ {idx: 18, exp: eq, fn: eq_255_int64},
+ {idx: 18, exp: ne, fn: ne_255_int64},
+ {idx: 19, exp: lt, fn: lt_256_int64},
+ {idx: 19, exp: le, fn: le_256_int64},
+ {idx: 19, exp: gt, fn: gt_256_int64},
+ {idx: 19, exp: ge, fn: ge_256_int64},
+ {idx: 19, exp: eq, fn: eq_256_int64},
+ {idx: 19, exp: ne, fn: ne_256_int64},
+ {idx: 20, exp: lt, fn: lt_32766_int64},
+ {idx: 20, exp: le, fn: le_32766_int64},
+ {idx: 20, exp: gt, fn: gt_32766_int64},
+ {idx: 20, exp: ge, fn: ge_32766_int64},
+ {idx: 20, exp: eq, fn: eq_32766_int64},
+ {idx: 20, exp: ne, fn: ne_32766_int64},
+ {idx: 21, exp: lt, fn: lt_32767_int64},
+ {idx: 21, exp: le, fn: le_32767_int64},
+ {idx: 21, exp: gt, fn: gt_32767_int64},
+ {idx: 21, exp: ge, fn: ge_32767_int64},
+ {idx: 21, exp: eq, fn: eq_32767_int64},
+ {idx: 21, exp: ne, fn: ne_32767_int64},
+ {idx: 22, exp: lt, fn: lt_32768_int64},
+ {idx: 22, exp: le, fn: le_32768_int64},
+ {idx: 22, exp: gt, fn: gt_32768_int64},
+ {idx: 22, exp: ge, fn: ge_32768_int64},
+ {idx: 22, exp: eq, fn: eq_32768_int64},
+ {idx: 22, exp: ne, fn: ne_32768_int64},
+ {idx: 23, exp: lt, fn: lt_65534_int64},
+ {idx: 23, exp: le, fn: le_65534_int64},
+ {idx: 23, exp: gt, fn: gt_65534_int64},
+ {idx: 23, exp: ge, fn: ge_65534_int64},
+ {idx: 23, exp: eq, fn: eq_65534_int64},
+ {idx: 23, exp: ne, fn: ne_65534_int64},
+ {idx: 24, exp: lt, fn: lt_65535_int64},
+ {idx: 24, exp: le, fn: le_65535_int64},
+ {idx: 24, exp: gt, fn: gt_65535_int64},
+ {idx: 24, exp: ge, fn: ge_65535_int64},
+ {idx: 24, exp: eq, fn: eq_65535_int64},
+ {idx: 24, exp: ne, fn: ne_65535_int64},
+ {idx: 25, exp: lt, fn: lt_65536_int64},
+ {idx: 25, exp: le, fn: le_65536_int64},
+ {idx: 25, exp: gt, fn: gt_65536_int64},
+ {idx: 25, exp: ge, fn: ge_65536_int64},
+ {idx: 25, exp: eq, fn: eq_65536_int64},
+ {idx: 25, exp: ne, fn: ne_65536_int64},
+ {idx: 26, exp: lt, fn: lt_2147483646_int64},
+ {idx: 26, exp: le, fn: le_2147483646_int64},
+ {idx: 26, exp: gt, fn: gt_2147483646_int64},
+ {idx: 26, exp: ge, fn: ge_2147483646_int64},
+ {idx: 26, exp: eq, fn: eq_2147483646_int64},
+ {idx: 26, exp: ne, fn: ne_2147483646_int64},
+ {idx: 27, exp: lt, fn: lt_2147483647_int64},
+ {idx: 27, exp: le, fn: le_2147483647_int64},
+ {idx: 27, exp: gt, fn: gt_2147483647_int64},
+ {idx: 27, exp: ge, fn: ge_2147483647_int64},
+ {idx: 27, exp: eq, fn: eq_2147483647_int64},
+ {idx: 27, exp: ne, fn: ne_2147483647_int64},
+ {idx: 28, exp: lt, fn: lt_2147483648_int64},
+ {idx: 28, exp: le, fn: le_2147483648_int64},
+ {idx: 28, exp: gt, fn: gt_2147483648_int64},
+ {idx: 28, exp: ge, fn: ge_2147483648_int64},
+ {idx: 28, exp: eq, fn: eq_2147483648_int64},
+ {idx: 28, exp: ne, fn: ne_2147483648_int64},
+ {idx: 29, exp: lt, fn: lt_4278190080_int64},
+ {idx: 29, exp: le, fn: le_4278190080_int64},
+ {idx: 29, exp: gt, fn: gt_4278190080_int64},
+ {idx: 29, exp: ge, fn: ge_4278190080_int64},
+ {idx: 29, exp: eq, fn: eq_4278190080_int64},
+ {idx: 29, exp: ne, fn: ne_4278190080_int64},
+ {idx: 30, exp: lt, fn: lt_4294967294_int64},
+ {idx: 30, exp: le, fn: le_4294967294_int64},
+ {idx: 30, exp: gt, fn: gt_4294967294_int64},
+ {idx: 30, exp: ge, fn: ge_4294967294_int64},
+ {idx: 30, exp: eq, fn: eq_4294967294_int64},
+ {idx: 30, exp: ne, fn: ne_4294967294_int64},
+ {idx: 31, exp: lt, fn: lt_4294967295_int64},
+ {idx: 31, exp: le, fn: le_4294967295_int64},
+ {idx: 31, exp: gt, fn: gt_4294967295_int64},
+ {idx: 31, exp: ge, fn: ge_4294967295_int64},
+ {idx: 31, exp: eq, fn: eq_4294967295_int64},
+ {idx: 31, exp: ne, fn: ne_4294967295_int64},
+ {idx: 32, exp: lt, fn: lt_4294967296_int64},
+ {idx: 32, exp: le, fn: le_4294967296_int64},
+ {idx: 32, exp: gt, fn: gt_4294967296_int64},
+ {idx: 32, exp: ge, fn: ge_4294967296_int64},
+ {idx: 32, exp: eq, fn: eq_4294967296_int64},
+ {idx: 32, exp: ne, fn: ne_4294967296_int64},
+ {idx: 33, exp: lt, fn: lt_1095216660480_int64},
+ {idx: 33, exp: le, fn: le_1095216660480_int64},
+ {idx: 33, exp: gt, fn: gt_1095216660480_int64},
+ {idx: 33, exp: ge, fn: ge_1095216660480_int64},
+ {idx: 33, exp: eq, fn: eq_1095216660480_int64},
+ {idx: 33, exp: ne, fn: ne_1095216660480_int64},
+ {idx: 34, exp: lt, fn: lt_9223372036854775806_int64},
+ {idx: 34, exp: le, fn: le_9223372036854775806_int64},
+ {idx: 34, exp: gt, fn: gt_9223372036854775806_int64},
+ {idx: 34, exp: ge, fn: ge_9223372036854775806_int64},
+ {idx: 34, exp: eq, fn: eq_9223372036854775806_int64},
+ {idx: 34, exp: ne, fn: ne_9223372036854775806_int64},
+ {idx: 35, exp: lt, fn: lt_9223372036854775807_int64},
+ {idx: 35, exp: le, fn: le_9223372036854775807_int64},
+ {idx: 35, exp: gt, fn: gt_9223372036854775807_int64},
+ {idx: 35, exp: ge, fn: ge_9223372036854775807_int64},
+ {idx: 35, exp: eq, fn: eq_9223372036854775807_int64},
+ {idx: 35, exp: ne, fn: ne_9223372036854775807_int64},
+}
+
+// int32 tests
+var int32_vals = []int32{
+ -2147483648,
+ -2147483647,
+ -32769,
+ -32768,
+ -32767,
+ -129,
+ -128,
+ -127,
+ -1,
+ 0,
+ 1,
+ 126,
+ 127,
+ 128,
+ 254,
+ 255,
+ 256,
+ 32766,
+ 32767,
+ 32768,
+ 65534,
+ 65535,
+ 65536,
+ 2147483646,
+ 2147483647,
+}
+
+func lt_neg2147483648_int32(x int32) bool { return x < -2147483648 }
+func le_neg2147483648_int32(x int32) bool { return x <= -2147483648 }
+func gt_neg2147483648_int32(x int32) bool { return x > -2147483648 }
+func ge_neg2147483648_int32(x int32) bool { return x >= -2147483648 }
+func eq_neg2147483648_int32(x int32) bool { return x == -2147483648 }
+func ne_neg2147483648_int32(x int32) bool { return x != -2147483648 }
+func lt_neg2147483647_int32(x int32) bool { return x < -2147483647 }
+func le_neg2147483647_int32(x int32) bool { return x <= -2147483647 }
+func gt_neg2147483647_int32(x int32) bool { return x > -2147483647 }
+func ge_neg2147483647_int32(x int32) bool { return x >= -2147483647 }
+func eq_neg2147483647_int32(x int32) bool { return x == -2147483647 }
+func ne_neg2147483647_int32(x int32) bool { return x != -2147483647 }
+func lt_neg32769_int32(x int32) bool { return x < -32769 }
+func le_neg32769_int32(x int32) bool { return x <= -32769 }
+func gt_neg32769_int32(x int32) bool { return x > -32769 }
+func ge_neg32769_int32(x int32) bool { return x >= -32769 }
+func eq_neg32769_int32(x int32) bool { return x == -32769 }
+func ne_neg32769_int32(x int32) bool { return x != -32769 }
+func lt_neg32768_int32(x int32) bool { return x < -32768 }
+func le_neg32768_int32(x int32) bool { return x <= -32768 }
+func gt_neg32768_int32(x int32) bool { return x > -32768 }
+func ge_neg32768_int32(x int32) bool { return x >= -32768 }
+func eq_neg32768_int32(x int32) bool { return x == -32768 }
+func ne_neg32768_int32(x int32) bool { return x != -32768 }
+func lt_neg32767_int32(x int32) bool { return x < -32767 }
+func le_neg32767_int32(x int32) bool { return x <= -32767 }
+func gt_neg32767_int32(x int32) bool { return x > -32767 }
+func ge_neg32767_int32(x int32) bool { return x >= -32767 }
+func eq_neg32767_int32(x int32) bool { return x == -32767 }
+func ne_neg32767_int32(x int32) bool { return x != -32767 }
+func lt_neg129_int32(x int32) bool { return x < -129 }
+func le_neg129_int32(x int32) bool { return x <= -129 }
+func gt_neg129_int32(x int32) bool { return x > -129 }
+func ge_neg129_int32(x int32) bool { return x >= -129 }
+func eq_neg129_int32(x int32) bool { return x == -129 }
+func ne_neg129_int32(x int32) bool { return x != -129 }
+func lt_neg128_int32(x int32) bool { return x < -128 }
+func le_neg128_int32(x int32) bool { return x <= -128 }
+func gt_neg128_int32(x int32) bool { return x > -128 }
+func ge_neg128_int32(x int32) bool { return x >= -128 }
+func eq_neg128_int32(x int32) bool { return x == -128 }
+func ne_neg128_int32(x int32) bool { return x != -128 }
+func lt_neg127_int32(x int32) bool { return x < -127 }
+func le_neg127_int32(x int32) bool { return x <= -127 }
+func gt_neg127_int32(x int32) bool { return x > -127 }
+func ge_neg127_int32(x int32) bool { return x >= -127 }
+func eq_neg127_int32(x int32) bool { return x == -127 }
+func ne_neg127_int32(x int32) bool { return x != -127 }
+func lt_neg1_int32(x int32) bool { return x < -1 }
+func le_neg1_int32(x int32) bool { return x <= -1 }
+func gt_neg1_int32(x int32) bool { return x > -1 }
+func ge_neg1_int32(x int32) bool { return x >= -1 }
+func eq_neg1_int32(x int32) bool { return x == -1 }
+func ne_neg1_int32(x int32) bool { return x != -1 }
+func lt_0_int32(x int32) bool { return x < 0 }
+func le_0_int32(x int32) bool { return x <= 0 }
+func gt_0_int32(x int32) bool { return x > 0 }
+func ge_0_int32(x int32) bool { return x >= 0 }
+func eq_0_int32(x int32) bool { return x == 0 }
+func ne_0_int32(x int32) bool { return x != 0 }
+func lt_1_int32(x int32) bool { return x < 1 }
+func le_1_int32(x int32) bool { return x <= 1 }
+func gt_1_int32(x int32) bool { return x > 1 }
+func ge_1_int32(x int32) bool { return x >= 1 }
+func eq_1_int32(x int32) bool { return x == 1 }
+func ne_1_int32(x int32) bool { return x != 1 }
+func lt_126_int32(x int32) bool { return x < 126 }
+func le_126_int32(x int32) bool { return x <= 126 }
+func gt_126_int32(x int32) bool { return x > 126 }
+func ge_126_int32(x int32) bool { return x >= 126 }
+func eq_126_int32(x int32) bool { return x == 126 }
+func ne_126_int32(x int32) bool { return x != 126 }
+func lt_127_int32(x int32) bool { return x < 127 }
+func le_127_int32(x int32) bool { return x <= 127 }
+func gt_127_int32(x int32) bool { return x > 127 }
+func ge_127_int32(x int32) bool { return x >= 127 }
+func eq_127_int32(x int32) bool { return x == 127 }
+func ne_127_int32(x int32) bool { return x != 127 }
+func lt_128_int32(x int32) bool { return x < 128 }
+func le_128_int32(x int32) bool { return x <= 128 }
+func gt_128_int32(x int32) bool { return x > 128 }
+func ge_128_int32(x int32) bool { return x >= 128 }
+func eq_128_int32(x int32) bool { return x == 128 }
+func ne_128_int32(x int32) bool { return x != 128 }
+func lt_254_int32(x int32) bool { return x < 254 }
+func le_254_int32(x int32) bool { return x <= 254 }
+func gt_254_int32(x int32) bool { return x > 254 }
+func ge_254_int32(x int32) bool { return x >= 254 }
+func eq_254_int32(x int32) bool { return x == 254 }
+func ne_254_int32(x int32) bool { return x != 254 }
+func lt_255_int32(x int32) bool { return x < 255 }
+func le_255_int32(x int32) bool { return x <= 255 }
+func gt_255_int32(x int32) bool { return x > 255 }
+func ge_255_int32(x int32) bool { return x >= 255 }
+func eq_255_int32(x int32) bool { return x == 255 }
+func ne_255_int32(x int32) bool { return x != 255 }
+func lt_256_int32(x int32) bool { return x < 256 }
+func le_256_int32(x int32) bool { return x <= 256 }
+func gt_256_int32(x int32) bool { return x > 256 }
+func ge_256_int32(x int32) bool { return x >= 256 }
+func eq_256_int32(x int32) bool { return x == 256 }
+func ne_256_int32(x int32) bool { return x != 256 }
+func lt_32766_int32(x int32) bool { return x < 32766 }
+func le_32766_int32(x int32) bool { return x <= 32766 }
+func gt_32766_int32(x int32) bool { return x > 32766 }
+func ge_32766_int32(x int32) bool { return x >= 32766 }
+func eq_32766_int32(x int32) bool { return x == 32766 }
+func ne_32766_int32(x int32) bool { return x != 32766 }
+func lt_32767_int32(x int32) bool { return x < 32767 }
+func le_32767_int32(x int32) bool { return x <= 32767 }
+func gt_32767_int32(x int32) bool { return x > 32767 }
+func ge_32767_int32(x int32) bool { return x >= 32767 }
+func eq_32767_int32(x int32) bool { return x == 32767 }
+func ne_32767_int32(x int32) bool { return x != 32767 }
+func lt_32768_int32(x int32) bool { return x < 32768 }
+func le_32768_int32(x int32) bool { return x <= 32768 }
+func gt_32768_int32(x int32) bool { return x > 32768 }
+func ge_32768_int32(x int32) bool { return x >= 32768 }
+func eq_32768_int32(x int32) bool { return x == 32768 }
+func ne_32768_int32(x int32) bool { return x != 32768 }
+func lt_65534_int32(x int32) bool { return x < 65534 }
+func le_65534_int32(x int32) bool { return x <= 65534 }
+func gt_65534_int32(x int32) bool { return x > 65534 }
+func ge_65534_int32(x int32) bool { return x >= 65534 }
+func eq_65534_int32(x int32) bool { return x == 65534 }
+func ne_65534_int32(x int32) bool { return x != 65534 }
+func lt_65535_int32(x int32) bool { return x < 65535 }
+func le_65535_int32(x int32) bool { return x <= 65535 }
+func gt_65535_int32(x int32) bool { return x > 65535 }
+func ge_65535_int32(x int32) bool { return x >= 65535 }
+func eq_65535_int32(x int32) bool { return x == 65535 }
+func ne_65535_int32(x int32) bool { return x != 65535 }
+func lt_65536_int32(x int32) bool { return x < 65536 }
+func le_65536_int32(x int32) bool { return x <= 65536 }
+func gt_65536_int32(x int32) bool { return x > 65536 }
+func ge_65536_int32(x int32) bool { return x >= 65536 }
+func eq_65536_int32(x int32) bool { return x == 65536 }
+func ne_65536_int32(x int32) bool { return x != 65536 }
+func lt_2147483646_int32(x int32) bool { return x < 2147483646 }
+func le_2147483646_int32(x int32) bool { return x <= 2147483646 }
+func gt_2147483646_int32(x int32) bool { return x > 2147483646 }
+func ge_2147483646_int32(x int32) bool { return x >= 2147483646 }
+func eq_2147483646_int32(x int32) bool { return x == 2147483646 }
+func ne_2147483646_int32(x int32) bool { return x != 2147483646 }
+func lt_2147483647_int32(x int32) bool { return x < 2147483647 }
+func le_2147483647_int32(x int32) bool { return x <= 2147483647 }
+func gt_2147483647_int32(x int32) bool { return x > 2147483647 }
+func ge_2147483647_int32(x int32) bool { return x >= 2147483647 }
+func eq_2147483647_int32(x int32) bool { return x == 2147483647 }
+func ne_2147483647_int32(x int32) bool { return x != 2147483647 }
+
+var int32_tests = []struct {
+ idx int // index of the constant used
+ exp result // expected results
+ fn func(int32) bool
+}{
+ {idx: 0, exp: lt, fn: lt_neg2147483648_int32},
+ {idx: 0, exp: le, fn: le_neg2147483648_int32},
+ {idx: 0, exp: gt, fn: gt_neg2147483648_int32},
+ {idx: 0, exp: ge, fn: ge_neg2147483648_int32},
+ {idx: 0, exp: eq, fn: eq_neg2147483648_int32},
+ {idx: 0, exp: ne, fn: ne_neg2147483648_int32},
+ {idx: 1, exp: lt, fn: lt_neg2147483647_int32},
+ {idx: 1, exp: le, fn: le_neg2147483647_int32},
+ {idx: 1, exp: gt, fn: gt_neg2147483647_int32},
+ {idx: 1, exp: ge, fn: ge_neg2147483647_int32},
+ {idx: 1, exp: eq, fn: eq_neg2147483647_int32},
+ {idx: 1, exp: ne, fn: ne_neg2147483647_int32},
+ {idx: 2, exp: lt, fn: lt_neg32769_int32},
+ {idx: 2, exp: le, fn: le_neg32769_int32},
+ {idx: 2, exp: gt, fn: gt_neg32769_int32},
+ {idx: 2, exp: ge, fn: ge_neg32769_int32},
+ {idx: 2, exp: eq, fn: eq_neg32769_int32},
+ {idx: 2, exp: ne, fn: ne_neg32769_int32},
+ {idx: 3, exp: lt, fn: lt_neg32768_int32},
+ {idx: 3, exp: le, fn: le_neg32768_int32},
+ {idx: 3, exp: gt, fn: gt_neg32768_int32},
+ {idx: 3, exp: ge, fn: ge_neg32768_int32},
+ {idx: 3, exp: eq, fn: eq_neg32768_int32},
+ {idx: 3, exp: ne, fn: ne_neg32768_int32},
+ {idx: 4, exp: lt, fn: lt_neg32767_int32},
+ {idx: 4, exp: le, fn: le_neg32767_int32},
+ {idx: 4, exp: gt, fn: gt_neg32767_int32},
+ {idx: 4, exp: ge, fn: ge_neg32767_int32},
+ {idx: 4, exp: eq, fn: eq_neg32767_int32},
+ {idx: 4, exp: ne, fn: ne_neg32767_int32},
+ {idx: 5, exp: lt, fn: lt_neg129_int32},
+ {idx: 5, exp: le, fn: le_neg129_int32},
+ {idx: 5, exp: gt, fn: gt_neg129_int32},
+ {idx: 5, exp: ge, fn: ge_neg129_int32},
+ {idx: 5, exp: eq, fn: eq_neg129_int32},
+ {idx: 5, exp: ne, fn: ne_neg129_int32},
+ {idx: 6, exp: lt, fn: lt_neg128_int32},
+ {idx: 6, exp: le, fn: le_neg128_int32},
+ {idx: 6, exp: gt, fn: gt_neg128_int32},
+ {idx: 6, exp: ge, fn: ge_neg128_int32},
+ {idx: 6, exp: eq, fn: eq_neg128_int32},
+ {idx: 6, exp: ne, fn: ne_neg128_int32},
+ {idx: 7, exp: lt, fn: lt_neg127_int32},
+ {idx: 7, exp: le, fn: le_neg127_int32},
+ {idx: 7, exp: gt, fn: gt_neg127_int32},
+ {idx: 7, exp: ge, fn: ge_neg127_int32},
+ {idx: 7, exp: eq, fn: eq_neg127_int32},
+ {idx: 7, exp: ne, fn: ne_neg127_int32},
+ {idx: 8, exp: lt, fn: lt_neg1_int32},
+ {idx: 8, exp: le, fn: le_neg1_int32},
+ {idx: 8, exp: gt, fn: gt_neg1_int32},
+ {idx: 8, exp: ge, fn: ge_neg1_int32},
+ {idx: 8, exp: eq, fn: eq_neg1_int32},
+ {idx: 8, exp: ne, fn: ne_neg1_int32},
+ {idx: 9, exp: lt, fn: lt_0_int32},
+ {idx: 9, exp: le, fn: le_0_int32},
+ {idx: 9, exp: gt, fn: gt_0_int32},
+ {idx: 9, exp: ge, fn: ge_0_int32},
+ {idx: 9, exp: eq, fn: eq_0_int32},
+ {idx: 9, exp: ne, fn: ne_0_int32},
+ {idx: 10, exp: lt, fn: lt_1_int32},
+ {idx: 10, exp: le, fn: le_1_int32},
+ {idx: 10, exp: gt, fn: gt_1_int32},
+ {idx: 10, exp: ge, fn: ge_1_int32},
+ {idx: 10, exp: eq, fn: eq_1_int32},
+ {idx: 10, exp: ne, fn: ne_1_int32},
+ {idx: 11, exp: lt, fn: lt_126_int32},
+ {idx: 11, exp: le, fn: le_126_int32},
+ {idx: 11, exp: gt, fn: gt_126_int32},
+ {idx: 11, exp: ge, fn: ge_126_int32},
+ {idx: 11, exp: eq, fn: eq_126_int32},
+ {idx: 11, exp: ne, fn: ne_126_int32},
+ {idx: 12, exp: lt, fn: lt_127_int32},
+ {idx: 12, exp: le, fn: le_127_int32},
+ {idx: 12, exp: gt, fn: gt_127_int32},
+ {idx: 12, exp: ge, fn: ge_127_int32},
+ {idx: 12, exp: eq, fn: eq_127_int32},
+ {idx: 12, exp: ne, fn: ne_127_int32},
+ {idx: 13, exp: lt, fn: lt_128_int32},
+ {idx: 13, exp: le, fn: le_128_int32},
+ {idx: 13, exp: gt, fn: gt_128_int32},
+ {idx: 13, exp: ge, fn: ge_128_int32},
+ {idx: 13, exp: eq, fn: eq_128_int32},
+ {idx: 13, exp: ne, fn: ne_128_int32},
+ {idx: 14, exp: lt, fn: lt_254_int32},
+ {idx: 14, exp: le, fn: le_254_int32},
+ {idx: 14, exp: gt, fn: gt_254_int32},
+ {idx: 14, exp: ge, fn: ge_254_int32},
+ {idx: 14, exp: eq, fn: eq_254_int32},
+ {idx: 14, exp: ne, fn: ne_254_int32},
+ {idx: 15, exp: lt, fn: lt_255_int32},
+ {idx: 15, exp: le, fn: le_255_int32},
+ {idx: 15, exp: gt, fn: gt_255_int32},
+ {idx: 15, exp: ge, fn: ge_255_int32},
+ {idx: 15, exp: eq, fn: eq_255_int32},
+ {idx: 15, exp: ne, fn: ne_255_int32},
+ {idx: 16, exp: lt, fn: lt_256_int32},
+ {idx: 16, exp: le, fn: le_256_int32},
+ {idx: 16, exp: gt, fn: gt_256_int32},
+ {idx: 16, exp: ge, fn: ge_256_int32},
+ {idx: 16, exp: eq, fn: eq_256_int32},
+ {idx: 16, exp: ne, fn: ne_256_int32},
+ {idx: 17, exp: lt, fn: lt_32766_int32},
+ {idx: 17, exp: le, fn: le_32766_int32},
+ {idx: 17, exp: gt, fn: gt_32766_int32},
+ {idx: 17, exp: ge, fn: ge_32766_int32},
+ {idx: 17, exp: eq, fn: eq_32766_int32},
+ {idx: 17, exp: ne, fn: ne_32766_int32},
+ {idx: 18, exp: lt, fn: lt_32767_int32},
+ {idx: 18, exp: le, fn: le_32767_int32},
+ {idx: 18, exp: gt, fn: gt_32767_int32},
+ {idx: 18, exp: ge, fn: ge_32767_int32},
+ {idx: 18, exp: eq, fn: eq_32767_int32},
+ {idx: 18, exp: ne, fn: ne_32767_int32},
+ {idx: 19, exp: lt, fn: lt_32768_int32},
+ {idx: 19, exp: le, fn: le_32768_int32},
+ {idx: 19, exp: gt, fn: gt_32768_int32},
+ {idx: 19, exp: ge, fn: ge_32768_int32},
+ {idx: 19, exp: eq, fn: eq_32768_int32},
+ {idx: 19, exp: ne, fn: ne_32768_int32},
+ {idx: 20, exp: lt, fn: lt_65534_int32},
+ {idx: 20, exp: le, fn: le_65534_int32},
+ {idx: 20, exp: gt, fn: gt_65534_int32},
+ {idx: 20, exp: ge, fn: ge_65534_int32},
+ {idx: 20, exp: eq, fn: eq_65534_int32},
+ {idx: 20, exp: ne, fn: ne_65534_int32},
+ {idx: 21, exp: lt, fn: lt_65535_int32},
+ {idx: 21, exp: le, fn: le_65535_int32},
+ {idx: 21, exp: gt, fn: gt_65535_int32},
+ {idx: 21, exp: ge, fn: ge_65535_int32},
+ {idx: 21, exp: eq, fn: eq_65535_int32},
+ {idx: 21, exp: ne, fn: ne_65535_int32},
+ {idx: 22, exp: lt, fn: lt_65536_int32},
+ {idx: 22, exp: le, fn: le_65536_int32},
+ {idx: 22, exp: gt, fn: gt_65536_int32},
+ {idx: 22, exp: ge, fn: ge_65536_int32},
+ {idx: 22, exp: eq, fn: eq_65536_int32},
+ {idx: 22, exp: ne, fn: ne_65536_int32},
+ {idx: 23, exp: lt, fn: lt_2147483646_int32},
+ {idx: 23, exp: le, fn: le_2147483646_int32},
+ {idx: 23, exp: gt, fn: gt_2147483646_int32},
+ {idx: 23, exp: ge, fn: ge_2147483646_int32},
+ {idx: 23, exp: eq, fn: eq_2147483646_int32},
+ {idx: 23, exp: ne, fn: ne_2147483646_int32},
+ {idx: 24, exp: lt, fn: lt_2147483647_int32},
+ {idx: 24, exp: le, fn: le_2147483647_int32},
+ {idx: 24, exp: gt, fn: gt_2147483647_int32},
+ {idx: 24, exp: ge, fn: ge_2147483647_int32},
+ {idx: 24, exp: eq, fn: eq_2147483647_int32},
+ {idx: 24, exp: ne, fn: ne_2147483647_int32},
+}
+
+// int16 tests
+var int16_vals = []int16{
+ -32768,
+ -32767,
+ -129,
+ -128,
+ -127,
+ -1,
+ 0,
+ 1,
+ 126,
+ 127,
+ 128,
+ 254,
+ 255,
+ 256,
+ 32766,
+ 32767,
+}
+
+func lt_neg32768_int16(x int16) bool { return x < -32768 }
+func le_neg32768_int16(x int16) bool { return x <= -32768 }
+func gt_neg32768_int16(x int16) bool { return x > -32768 }
+func ge_neg32768_int16(x int16) bool { return x >= -32768 }
+func eq_neg32768_int16(x int16) bool { return x == -32768 }
+func ne_neg32768_int16(x int16) bool { return x != -32768 }
+func lt_neg32767_int16(x int16) bool { return x < -32767 }
+func le_neg32767_int16(x int16) bool { return x <= -32767 }
+func gt_neg32767_int16(x int16) bool { return x > -32767 }
+func ge_neg32767_int16(x int16) bool { return x >= -32767 }
+func eq_neg32767_int16(x int16) bool { return x == -32767 }
+func ne_neg32767_int16(x int16) bool { return x != -32767 }
+func lt_neg129_int16(x int16) bool { return x < -129 }
+func le_neg129_int16(x int16) bool { return x <= -129 }
+func gt_neg129_int16(x int16) bool { return x > -129 }
+func ge_neg129_int16(x int16) bool { return x >= -129 }
+func eq_neg129_int16(x int16) bool { return x == -129 }
+func ne_neg129_int16(x int16) bool { return x != -129 }
+func lt_neg128_int16(x int16) bool { return x < -128 }
+func le_neg128_int16(x int16) bool { return x <= -128 }
+func gt_neg128_int16(x int16) bool { return x > -128 }
+func ge_neg128_int16(x int16) bool { return x >= -128 }
+func eq_neg128_int16(x int16) bool { return x == -128 }
+func ne_neg128_int16(x int16) bool { return x != -128 }
+func lt_neg127_int16(x int16) bool { return x < -127 }
+func le_neg127_int16(x int16) bool { return x <= -127 }
+func gt_neg127_int16(x int16) bool { return x > -127 }
+func ge_neg127_int16(x int16) bool { return x >= -127 }
+func eq_neg127_int16(x int16) bool { return x == -127 }
+func ne_neg127_int16(x int16) bool { return x != -127 }
+func lt_neg1_int16(x int16) bool { return x < -1 }
+func le_neg1_int16(x int16) bool { return x <= -1 }
+func gt_neg1_int16(x int16) bool { return x > -1 }
+func ge_neg1_int16(x int16) bool { return x >= -1 }
+func eq_neg1_int16(x int16) bool { return x == -1 }
+func ne_neg1_int16(x int16) bool { return x != -1 }
+func lt_0_int16(x int16) bool { return x < 0 }
+func le_0_int16(x int16) bool { return x <= 0 }
+func gt_0_int16(x int16) bool { return x > 0 }
+func ge_0_int16(x int16) bool { return x >= 0 }
+func eq_0_int16(x int16) bool { return x == 0 }
+func ne_0_int16(x int16) bool { return x != 0 }
+func lt_1_int16(x int16) bool { return x < 1 }
+func le_1_int16(x int16) bool { return x <= 1 }
+func gt_1_int16(x int16) bool { return x > 1 }
+func ge_1_int16(x int16) bool { return x >= 1 }
+func eq_1_int16(x int16) bool { return x == 1 }
+func ne_1_int16(x int16) bool { return x != 1 }
+func lt_126_int16(x int16) bool { return x < 126 }
+func le_126_int16(x int16) bool { return x <= 126 }
+func gt_126_int16(x int16) bool { return x > 126 }
+func ge_126_int16(x int16) bool { return x >= 126 }
+func eq_126_int16(x int16) bool { return x == 126 }
+func ne_126_int16(x int16) bool { return x != 126 }
+func lt_127_int16(x int16) bool { return x < 127 }
+func le_127_int16(x int16) bool { return x <= 127 }
+func gt_127_int16(x int16) bool { return x > 127 }
+func ge_127_int16(x int16) bool { return x >= 127 }
+func eq_127_int16(x int16) bool { return x == 127 }
+func ne_127_int16(x int16) bool { return x != 127 }
+func lt_128_int16(x int16) bool { return x < 128 }
+func le_128_int16(x int16) bool { return x <= 128 }
+func gt_128_int16(x int16) bool { return x > 128 }
+func ge_128_int16(x int16) bool { return x >= 128 }
+func eq_128_int16(x int16) bool { return x == 128 }
+func ne_128_int16(x int16) bool { return x != 128 }
+func lt_254_int16(x int16) bool { return x < 254 }
+func le_254_int16(x int16) bool { return x <= 254 }
+func gt_254_int16(x int16) bool { return x > 254 }
+func ge_254_int16(x int16) bool { return x >= 254 }
+func eq_254_int16(x int16) bool { return x == 254 }
+func ne_254_int16(x int16) bool { return x != 254 }
+func lt_255_int16(x int16) bool { return x < 255 }
+func le_255_int16(x int16) bool { return x <= 255 }
+func gt_255_int16(x int16) bool { return x > 255 }
+func ge_255_int16(x int16) bool { return x >= 255 }
+func eq_255_int16(x int16) bool { return x == 255 }
+func ne_255_int16(x int16) bool { return x != 255 }
+func lt_256_int16(x int16) bool { return x < 256 }
+func le_256_int16(x int16) bool { return x <= 256 }
+func gt_256_int16(x int16) bool { return x > 256 }
+func ge_256_int16(x int16) bool { return x >= 256 }
+func eq_256_int16(x int16) bool { return x == 256 }
+func ne_256_int16(x int16) bool { return x != 256 }
+func lt_32766_int16(x int16) bool { return x < 32766 }
+func le_32766_int16(x int16) bool { return x <= 32766 }
+func gt_32766_int16(x int16) bool { return x > 32766 }
+func ge_32766_int16(x int16) bool { return x >= 32766 }
+func eq_32766_int16(x int16) bool { return x == 32766 }
+func ne_32766_int16(x int16) bool { return x != 32766 }
+func lt_32767_int16(x int16) bool { return x < 32767 }
+func le_32767_int16(x int16) bool { return x <= 32767 }
+func gt_32767_int16(x int16) bool { return x > 32767 }
+func ge_32767_int16(x int16) bool { return x >= 32767 }
+func eq_32767_int16(x int16) bool { return x == 32767 }
+func ne_32767_int16(x int16) bool { return x != 32767 }
+
+var int16_tests = []struct {
+ idx int // index of the constant used
+ exp result // expected results
+ fn func(int16) bool
+}{
+ {idx: 0, exp: lt, fn: lt_neg32768_int16},
+ {idx: 0, exp: le, fn: le_neg32768_int16},
+ {idx: 0, exp: gt, fn: gt_neg32768_int16},
+ {idx: 0, exp: ge, fn: ge_neg32768_int16},
+ {idx: 0, exp: eq, fn: eq_neg32768_int16},
+ {idx: 0, exp: ne, fn: ne_neg32768_int16},
+ {idx: 1, exp: lt, fn: lt_neg32767_int16},
+ {idx: 1, exp: le, fn: le_neg32767_int16},
+ {idx: 1, exp: gt, fn: gt_neg32767_int16},
+ {idx: 1, exp: ge, fn: ge_neg32767_int16},
+ {idx: 1, exp: eq, fn: eq_neg32767_int16},
+ {idx: 1, exp: ne, fn: ne_neg32767_int16},
+ {idx: 2, exp: lt, fn: lt_neg129_int16},
+ {idx: 2, exp: le, fn: le_neg129_int16},
+ {idx: 2, exp: gt, fn: gt_neg129_int16},
+ {idx: 2, exp: ge, fn: ge_neg129_int16},
+ {idx: 2, exp: eq, fn: eq_neg129_int16},
+ {idx: 2, exp: ne, fn: ne_neg129_int16},
+ {idx: 3, exp: lt, fn: lt_neg128_int16},
+ {idx: 3, exp: le, fn: le_neg128_int16},
+ {idx: 3, exp: gt, fn: gt_neg128_int16},
+ {idx: 3, exp: ge, fn: ge_neg128_int16},
+ {idx: 3, exp: eq, fn: eq_neg128_int16},
+ {idx: 3, exp: ne, fn: ne_neg128_int16},
+ {idx: 4, exp: lt, fn: lt_neg127_int16},
+ {idx: 4, exp: le, fn: le_neg127_int16},
+ {idx: 4, exp: gt, fn: gt_neg127_int16},
+ {idx: 4, exp: ge, fn: ge_neg127_int16},
+ {idx: 4, exp: eq, fn: eq_neg127_int16},
+ {idx: 4, exp: ne, fn: ne_neg127_int16},
+ {idx: 5, exp: lt, fn: lt_neg1_int16},
+ {idx: 5, exp: le, fn: le_neg1_int16},
+ {idx: 5, exp: gt, fn: gt_neg1_int16},
+ {idx: 5, exp: ge, fn: ge_neg1_int16},
+ {idx: 5, exp: eq, fn: eq_neg1_int16},
+ {idx: 5, exp: ne, fn: ne_neg1_int16},
+ {idx: 6, exp: lt, fn: lt_0_int16},
+ {idx: 6, exp: le, fn: le_0_int16},
+ {idx: 6, exp: gt, fn: gt_0_int16},
+ {idx: 6, exp: ge, fn: ge_0_int16},
+ {idx: 6, exp: eq, fn: eq_0_int16},
+ {idx: 6, exp: ne, fn: ne_0_int16},
+ {idx: 7, exp: lt, fn: lt_1_int16},
+ {idx: 7, exp: le, fn: le_1_int16},
+ {idx: 7, exp: gt, fn: gt_1_int16},
+ {idx: 7, exp: ge, fn: ge_1_int16},
+ {idx: 7, exp: eq, fn: eq_1_int16},
+ {idx: 7, exp: ne, fn: ne_1_int16},
+ {idx: 8, exp: lt, fn: lt_126_int16},
+ {idx: 8, exp: le, fn: le_126_int16},
+ {idx: 8, exp: gt, fn: gt_126_int16},
+ {idx: 8, exp: ge, fn: ge_126_int16},
+ {idx: 8, exp: eq, fn: eq_126_int16},
+ {idx: 8, exp: ne, fn: ne_126_int16},
+ {idx: 9, exp: lt, fn: lt_127_int16},
+ {idx: 9, exp: le, fn: le_127_int16},
+ {idx: 9, exp: gt, fn: gt_127_int16},
+ {idx: 9, exp: ge, fn: ge_127_int16},
+ {idx: 9, exp: eq, fn: eq_127_int16},
+ {idx: 9, exp: ne, fn: ne_127_int16},
+ {idx: 10, exp: lt, fn: lt_128_int16},
+ {idx: 10, exp: le, fn: le_128_int16},
+ {idx: 10, exp: gt, fn: gt_128_int16},
+ {idx: 10, exp: ge, fn: ge_128_int16},
+ {idx: 10, exp: eq, fn: eq_128_int16},
+ {idx: 10, exp: ne, fn: ne_128_int16},
+ {idx: 11, exp: lt, fn: lt_254_int16},
+ {idx: 11, exp: le, fn: le_254_int16},
+ {idx: 11, exp: gt, fn: gt_254_int16},
+ {idx: 11, exp: ge, fn: ge_254_int16},
+ {idx: 11, exp: eq, fn: eq_254_int16},
+ {idx: 11, exp: ne, fn: ne_254_int16},
+ {idx: 12, exp: lt, fn: lt_255_int16},
+ {idx: 12, exp: le, fn: le_255_int16},
+ {idx: 12, exp: gt, fn: gt_255_int16},
+ {idx: 12, exp: ge, fn: ge_255_int16},
+ {idx: 12, exp: eq, fn: eq_255_int16},
+ {idx: 12, exp: ne, fn: ne_255_int16},
+ {idx: 13, exp: lt, fn: lt_256_int16},
+ {idx: 13, exp: le, fn: le_256_int16},
+ {idx: 13, exp: gt, fn: gt_256_int16},
+ {idx: 13, exp: ge, fn: ge_256_int16},
+ {idx: 13, exp: eq, fn: eq_256_int16},
+ {idx: 13, exp: ne, fn: ne_256_int16},
+ {idx: 14, exp: lt, fn: lt_32766_int16},
+ {idx: 14, exp: le, fn: le_32766_int16},
+ {idx: 14, exp: gt, fn: gt_32766_int16},
+ {idx: 14, exp: ge, fn: ge_32766_int16},
+ {idx: 14, exp: eq, fn: eq_32766_int16},
+ {idx: 14, exp: ne, fn: ne_32766_int16},
+ {idx: 15, exp: lt, fn: lt_32767_int16},
+ {idx: 15, exp: le, fn: le_32767_int16},
+ {idx: 15, exp: gt, fn: gt_32767_int16},
+ {idx: 15, exp: ge, fn: ge_32767_int16},
+ {idx: 15, exp: eq, fn: eq_32767_int16},
+ {idx: 15, exp: ne, fn: ne_32767_int16},
+}
+
+// int8 tests
+var int8_vals = []int8{
+ -128,
+ -127,
+ -1,
+ 0,
+ 1,
+ 126,
+ 127,
+}
+
+func lt_neg128_int8(x int8) bool { return x < -128 }
+func le_neg128_int8(x int8) bool { return x <= -128 }
+func gt_neg128_int8(x int8) bool { return x > -128 }
+func ge_neg128_int8(x int8) bool { return x >= -128 }
+func eq_neg128_int8(x int8) bool { return x == -128 }
+func ne_neg128_int8(x int8) bool { return x != -128 }
+func lt_neg127_int8(x int8) bool { return x < -127 }
+func le_neg127_int8(x int8) bool { return x <= -127 }
+func gt_neg127_int8(x int8) bool { return x > -127 }
+func ge_neg127_int8(x int8) bool { return x >= -127 }
+func eq_neg127_int8(x int8) bool { return x == -127 }
+func ne_neg127_int8(x int8) bool { return x != -127 }
+func lt_neg1_int8(x int8) bool { return x < -1 }
+func le_neg1_int8(x int8) bool { return x <= -1 }
+func gt_neg1_int8(x int8) bool { return x > -1 }
+func ge_neg1_int8(x int8) bool { return x >= -1 }
+func eq_neg1_int8(x int8) bool { return x == -1 }
+func ne_neg1_int8(x int8) bool { return x != -1 }
+func lt_0_int8(x int8) bool { return x < 0 }
+func le_0_int8(x int8) bool { return x <= 0 }
+func gt_0_int8(x int8) bool { return x > 0 }
+func ge_0_int8(x int8) bool { return x >= 0 }
+func eq_0_int8(x int8) bool { return x == 0 }
+func ne_0_int8(x int8) bool { return x != 0 }
+func lt_1_int8(x int8) bool { return x < 1 }
+func le_1_int8(x int8) bool { return x <= 1 }
+func gt_1_int8(x int8) bool { return x > 1 }
+func ge_1_int8(x int8) bool { return x >= 1 }
+func eq_1_int8(x int8) bool { return x == 1 }
+func ne_1_int8(x int8) bool { return x != 1 }
+func lt_126_int8(x int8) bool { return x < 126 }
+func le_126_int8(x int8) bool { return x <= 126 }
+func gt_126_int8(x int8) bool { return x > 126 }
+func ge_126_int8(x int8) bool { return x >= 126 }
+func eq_126_int8(x int8) bool { return x == 126 }
+func ne_126_int8(x int8) bool { return x != 126 }
+func lt_127_int8(x int8) bool { return x < 127 }
+func le_127_int8(x int8) bool { return x <= 127 }
+func gt_127_int8(x int8) bool { return x > 127 }
+func ge_127_int8(x int8) bool { return x >= 127 }
+func eq_127_int8(x int8) bool { return x == 127 }
+func ne_127_int8(x int8) bool { return x != 127 }
+
+var int8_tests = []struct {
+ idx int // index of the constant used
+ exp result // expected results
+ fn func(int8) bool
+}{
+ {idx: 0, exp: lt, fn: lt_neg128_int8},
+ {idx: 0, exp: le, fn: le_neg128_int8},
+ {idx: 0, exp: gt, fn: gt_neg128_int8},
+ {idx: 0, exp: ge, fn: ge_neg128_int8},
+ {idx: 0, exp: eq, fn: eq_neg128_int8},
+ {idx: 0, exp: ne, fn: ne_neg128_int8},
+ {idx: 1, exp: lt, fn: lt_neg127_int8},
+ {idx: 1, exp: le, fn: le_neg127_int8},
+ {idx: 1, exp: gt, fn: gt_neg127_int8},
+ {idx: 1, exp: ge, fn: ge_neg127_int8},
+ {idx: 1, exp: eq, fn: eq_neg127_int8},
+ {idx: 1, exp: ne, fn: ne_neg127_int8},
+ {idx: 2, exp: lt, fn: lt_neg1_int8},
+ {idx: 2, exp: le, fn: le_neg1_int8},
+ {idx: 2, exp: gt, fn: gt_neg1_int8},
+ {idx: 2, exp: ge, fn: ge_neg1_int8},
+ {idx: 2, exp: eq, fn: eq_neg1_int8},
+ {idx: 2, exp: ne, fn: ne_neg1_int8},
+ {idx: 3, exp: lt, fn: lt_0_int8},
+ {idx: 3, exp: le, fn: le_0_int8},
+ {idx: 3, exp: gt, fn: gt_0_int8},
+ {idx: 3, exp: ge, fn: ge_0_int8},
+ {idx: 3, exp: eq, fn: eq_0_int8},
+ {idx: 3, exp: ne, fn: ne_0_int8},
+ {idx: 4, exp: lt, fn: lt_1_int8},
+ {idx: 4, exp: le, fn: le_1_int8},
+ {idx: 4, exp: gt, fn: gt_1_int8},
+ {idx: 4, exp: ge, fn: ge_1_int8},
+ {idx: 4, exp: eq, fn: eq_1_int8},
+ {idx: 4, exp: ne, fn: ne_1_int8},
+ {idx: 5, exp: lt, fn: lt_126_int8},
+ {idx: 5, exp: le, fn: le_126_int8},
+ {idx: 5, exp: gt, fn: gt_126_int8},
+ {idx: 5, exp: ge, fn: ge_126_int8},
+ {idx: 5, exp: eq, fn: eq_126_int8},
+ {idx: 5, exp: ne, fn: ne_126_int8},
+ {idx: 6, exp: lt, fn: lt_127_int8},
+ {idx: 6, exp: le, fn: le_127_int8},
+ {idx: 6, exp: gt, fn: gt_127_int8},
+ {idx: 6, exp: ge, fn: ge_127_int8},
+ {idx: 6, exp: eq, fn: eq_127_int8},
+ {idx: 6, exp: ne, fn: ne_127_int8},
+}
+
+// TestComparisonsConst tests results for comparison operations against constants.
+func TestComparisonsConst(t *testing.T) {
+ for i, test := range uint64_tests {
+ for j, x := range uint64_vals {
+ want := test.exp.l
+ if j == test.idx {
+ want = test.exp.e
+ } else if j > test.idx {
+ want = test.exp.r
+ }
+ if test.fn(x) != want {
+ fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()
+ t.Errorf("test failed: %v(%v) != %v [type=uint64 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx)
+ }
+ }
+ }
+ for i, test := range uint32_tests {
+ for j, x := range uint32_vals {
+ want := test.exp.l
+ if j == test.idx {
+ want = test.exp.e
+ } else if j > test.idx {
+ want = test.exp.r
+ }
+ if test.fn(x) != want {
+ fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()
+ t.Errorf("test failed: %v(%v) != %v [type=uint32 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx)
+ }
+ }
+ }
+ for i, test := range uint16_tests {
+ for j, x := range uint16_vals {
+ want := test.exp.l
+ if j == test.idx {
+ want = test.exp.e
+ } else if j > test.idx {
+ want = test.exp.r
+ }
+ if test.fn(x) != want {
+ fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()
+ t.Errorf("test failed: %v(%v) != %v [type=uint16 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx)
+ }
+ }
+ }
+ for i, test := range uint8_tests {
+ for j, x := range uint8_vals {
+ want := test.exp.l
+ if j == test.idx {
+ want = test.exp.e
+ } else if j > test.idx {
+ want = test.exp.r
+ }
+ if test.fn(x) != want {
+ fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()
+ t.Errorf("test failed: %v(%v) != %v [type=uint8 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx)
+ }
+ }
+ }
+ for i, test := range int64_tests {
+ for j, x := range int64_vals {
+ want := test.exp.l
+ if j == test.idx {
+ want = test.exp.e
+ } else if j > test.idx {
+ want = test.exp.r
+ }
+ if test.fn(x) != want {
+ fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()
+ t.Errorf("test failed: %v(%v) != %v [type=int64 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx)
+ }
+ }
+ }
+ for i, test := range int32_tests {
+ for j, x := range int32_vals {
+ want := test.exp.l
+ if j == test.idx {
+ want = test.exp.e
+ } else if j > test.idx {
+ want = test.exp.r
+ }
+ if test.fn(x) != want {
+ fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()
+ t.Errorf("test failed: %v(%v) != %v [type=int32 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx)
+ }
+ }
+ }
+ for i, test := range int16_tests {
+ for j, x := range int16_vals {
+ want := test.exp.l
+ if j == test.idx {
+ want = test.exp.e
+ } else if j > test.idx {
+ want = test.exp.r
+ }
+ if test.fn(x) != want {
+ fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()
+ t.Errorf("test failed: %v(%v) != %v [type=int16 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx)
+ }
+ }
+ }
+ for i, test := range int8_tests {
+ for j, x := range int8_vals {
+ want := test.exp.l
+ if j == test.idx {
+ want = test.exp.e
+ } else if j > test.idx {
+ want = test.exp.r
+ }
+ if test.fn(x) != want {
+ fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()
+ t.Errorf("test failed: %v(%v) != %v [type=int8 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx)
+ }
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/cmp_test.go b/src/cmd/compile/internal/gc/testdata/cmp_test.go
new file mode 100644
index 0000000..06b58f2
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/cmp_test.go
@@ -0,0 +1,37 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// cmp_ssa.go tests compare simplification operations.
+package main
+
+import "testing"
+
+//go:noinline
+func eq_ssa(a int64) bool {
+ return 4+a == 10
+}
+
+//go:noinline
+func neq_ssa(a int64) bool {
+ return 10 != a+4
+}
+
+func testCmp(t *testing.T) {
+ if wanted, got := true, eq_ssa(6); wanted != got {
+ t.Errorf("eq_ssa: expected %v, got %v\n", wanted, got)
+ }
+ if wanted, got := false, eq_ssa(7); wanted != got {
+ t.Errorf("eq_ssa: expected %v, got %v\n", wanted, got)
+ }
+ if wanted, got := false, neq_ssa(6); wanted != got {
+ t.Errorf("neq_ssa: expected %v, got %v\n", wanted, got)
+ }
+ if wanted, got := true, neq_ssa(7); wanted != got {
+ t.Errorf("neq_ssa: expected %v, got %v\n", wanted, got)
+ }
+}
+
+func TestCmp(t *testing.T) {
+ testCmp(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/compound_test.go b/src/cmd/compile/internal/gc/testdata/compound_test.go
new file mode 100644
index 0000000..4ae464d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/compound_test.go
@@ -0,0 +1,128 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test compound objects
+
+package main
+
+import (
+ "testing"
+)
+
+func string_ssa(a, b string, x bool) string {
+ s := ""
+ if x {
+ s = a
+ } else {
+ s = b
+ }
+ return s
+}
+
+func testString(t *testing.T) {
+ a := "foo"
+ b := "barz"
+ if want, got := a, string_ssa(a, b, true); got != want {
+ t.Errorf("string_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+ }
+ if want, got := b, string_ssa(a, b, false); got != want {
+ t.Errorf("string_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+ }
+}
+
+//go:noinline
+func complex64_ssa(a, b complex64, x bool) complex64 {
+ var c complex64
+ if x {
+ c = a
+ } else {
+ c = b
+ }
+ return c
+}
+
+//go:noinline
+func complex128_ssa(a, b complex128, x bool) complex128 {
+ var c complex128
+ if x {
+ c = a
+ } else {
+ c = b
+ }
+ return c
+}
+
+func testComplex64(t *testing.T) {
+ var a complex64 = 1 + 2i
+ var b complex64 = 3 + 4i
+
+ if want, got := a, complex64_ssa(a, b, true); got != want {
+ t.Errorf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+ }
+ if want, got := b, complex64_ssa(a, b, false); got != want {
+ t.Errorf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+ }
+}
+
+func testComplex128(t *testing.T) {
+ var a complex128 = 1 + 2i
+ var b complex128 = 3 + 4i
+
+ if want, got := a, complex128_ssa(a, b, true); got != want {
+ t.Errorf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+ }
+ if want, got := b, complex128_ssa(a, b, false); got != want {
+ t.Errorf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+ }
+}
+
+func slice_ssa(a, b []byte, x bool) []byte {
+ var s []byte
+ if x {
+ s = a
+ } else {
+ s = b
+ }
+ return s
+}
+
+func testSlice(t *testing.T) {
+ a := []byte{3, 4, 5}
+ b := []byte{7, 8, 9}
+ if want, got := byte(3), slice_ssa(a, b, true)[0]; got != want {
+ t.Errorf("slice_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+ }
+ if want, got := byte(7), slice_ssa(a, b, false)[0]; got != want {
+ t.Errorf("slice_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+ }
+}
+
+func interface_ssa(a, b interface{}, x bool) interface{} {
+ var s interface{}
+ if x {
+ s = a
+ } else {
+ s = b
+ }
+ return s
+}
+
+func testInterface(t *testing.T) {
+ a := interface{}(3)
+ b := interface{}(4)
+ if want, got := 3, interface_ssa(a, b, true).(int); got != want {
+ t.Errorf("interface_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+ }
+ if want, got := 4, interface_ssa(a, b, false).(int); got != want {
+ t.Errorf("interface_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+ }
+}
+
+func TestCompound(t *testing.T) {
+ testString(t)
+ testSlice(t)
+ testInterface(t)
+ testComplex64(t)
+ testComplex128(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/copy_test.go b/src/cmd/compile/internal/gc/testdata/copy_test.go
new file mode 100644
index 0000000..c29611d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/copy_test.go
@@ -0,0 +1,760 @@
+// Code generated by gen/copyGen.go. DO NOT EDIT.
+
+package main
+
+import "testing"
+
+type T1 struct {
+ pre [8]byte
+ mid [1]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1copy_ssa(y, x *[1]byte) {
+ *y = *x
+}
+func testCopy1(t *testing.T) {
+ a := T1{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1]byte{0}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1]byte{100}
+ t1copy_ssa(&a.mid, &x)
+ want := T1{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1]byte{100}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T2 struct {
+ pre [8]byte
+ mid [2]byte
+ post [8]byte
+}
+
+//go:noinline
+func t2copy_ssa(y, x *[2]byte) {
+ *y = *x
+}
+func testCopy2(t *testing.T) {
+ a := T2{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [2]byte{0, 1}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [2]byte{100, 101}
+ t2copy_ssa(&a.mid, &x)
+ want := T2{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [2]byte{100, 101}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t2copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T3 struct {
+ pre [8]byte
+ mid [3]byte
+ post [8]byte
+}
+
+//go:noinline
+func t3copy_ssa(y, x *[3]byte) {
+ *y = *x
+}
+func testCopy3(t *testing.T) {
+ a := T3{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [3]byte{0, 1, 2}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [3]byte{100, 101, 102}
+ t3copy_ssa(&a.mid, &x)
+ want := T3{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [3]byte{100, 101, 102}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t3copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T4 struct {
+ pre [8]byte
+ mid [4]byte
+ post [8]byte
+}
+
+//go:noinline
+func t4copy_ssa(y, x *[4]byte) {
+ *y = *x
+}
+func testCopy4(t *testing.T) {
+ a := T4{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [4]byte{0, 1, 2, 3}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [4]byte{100, 101, 102, 103}
+ t4copy_ssa(&a.mid, &x)
+ want := T4{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [4]byte{100, 101, 102, 103}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t4copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T5 struct {
+ pre [8]byte
+ mid [5]byte
+ post [8]byte
+}
+
+//go:noinline
+func t5copy_ssa(y, x *[5]byte) {
+ *y = *x
+}
+func testCopy5(t *testing.T) {
+ a := T5{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [5]byte{0, 1, 2, 3, 4}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [5]byte{100, 101, 102, 103, 104}
+ t5copy_ssa(&a.mid, &x)
+ want := T5{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [5]byte{100, 101, 102, 103, 104}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t5copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T6 struct {
+ pre [8]byte
+ mid [6]byte
+ post [8]byte
+}
+
+//go:noinline
+func t6copy_ssa(y, x *[6]byte) {
+ *y = *x
+}
+func testCopy6(t *testing.T) {
+ a := T6{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [6]byte{0, 1, 2, 3, 4, 5}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [6]byte{100, 101, 102, 103, 104, 105}
+ t6copy_ssa(&a.mid, &x)
+ want := T6{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [6]byte{100, 101, 102, 103, 104, 105}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t6copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T7 struct {
+ pre [8]byte
+ mid [7]byte
+ post [8]byte
+}
+
+//go:noinline
+func t7copy_ssa(y, x *[7]byte) {
+ *y = *x
+}
+func testCopy7(t *testing.T) {
+ a := T7{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [7]byte{0, 1, 2, 3, 4, 5, 6}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [7]byte{100, 101, 102, 103, 104, 105, 106}
+ t7copy_ssa(&a.mid, &x)
+ want := T7{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [7]byte{100, 101, 102, 103, 104, 105, 106}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t7copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T8 struct {
+ pre [8]byte
+ mid [8]byte
+ post [8]byte
+}
+
+//go:noinline
+func t8copy_ssa(y, x *[8]byte) {
+ *y = *x
+}
+func testCopy8(t *testing.T) {
+ a := T8{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [8]byte{0, 1, 2, 3, 4, 5, 6, 7}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [8]byte{100, 101, 102, 103, 104, 105, 106, 107}
+ t8copy_ssa(&a.mid, &x)
+ want := T8{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [8]byte{100, 101, 102, 103, 104, 105, 106, 107}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t8copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T9 struct {
+ pre [8]byte
+ mid [9]byte
+ post [8]byte
+}
+
+//go:noinline
+func t9copy_ssa(y, x *[9]byte) {
+ *y = *x
+}
+func testCopy9(t *testing.T) {
+ a := T9{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [9]byte{0, 1, 2, 3, 4, 5, 6, 7, 8}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [9]byte{100, 101, 102, 103, 104, 105, 106, 107, 108}
+ t9copy_ssa(&a.mid, &x)
+ want := T9{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [9]byte{100, 101, 102, 103, 104, 105, 106, 107, 108}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t9copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T10 struct {
+ pre [8]byte
+ mid [10]byte
+ post [8]byte
+}
+
+//go:noinline
+func t10copy_ssa(y, x *[10]byte) {
+ *y = *x
+}
+func testCopy10(t *testing.T) {
+ a := T10{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [10]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109}
+ t10copy_ssa(&a.mid, &x)
+ want := T10{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [10]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t10copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T15 struct {
+ pre [8]byte
+ mid [15]byte
+ post [8]byte
+}
+
+//go:noinline
+func t15copy_ssa(y, x *[15]byte) {
+ *y = *x
+}
+func testCopy15(t *testing.T) {
+ a := T15{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [15]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [15]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114}
+ t15copy_ssa(&a.mid, &x)
+ want := T15{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [15]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t15copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T16 struct {
+ pre [8]byte
+ mid [16]byte
+ post [8]byte
+}
+
+//go:noinline
+func t16copy_ssa(y, x *[16]byte) {
+ *y = *x
+}
+func testCopy16(t *testing.T) {
+ a := T16{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [16]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115}
+ t16copy_ssa(&a.mid, &x)
+ want := T16{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [16]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t16copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T17 struct {
+ pre [8]byte
+ mid [17]byte
+ post [8]byte
+}
+
+//go:noinline
+func t17copy_ssa(y, x *[17]byte) {
+ *y = *x
+}
+func testCopy17(t *testing.T) {
+ a := T17{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [17]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [17]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116}
+ t17copy_ssa(&a.mid, &x)
+ want := T17{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [17]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t17copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T23 struct {
+ pre [8]byte
+ mid [23]byte
+ post [8]byte
+}
+
+//go:noinline
+func t23copy_ssa(y, x *[23]byte) {
+ *y = *x
+}
+func testCopy23(t *testing.T) {
+ a := T23{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [23]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [23]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}
+ t23copy_ssa(&a.mid, &x)
+ want := T23{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [23]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t23copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T24 struct {
+ pre [8]byte
+ mid [24]byte
+ post [8]byte
+}
+
+//go:noinline
+func t24copy_ssa(y, x *[24]byte) {
+ *y = *x
+}
+func testCopy24(t *testing.T) {
+ a := T24{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [24]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [24]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123}
+ t24copy_ssa(&a.mid, &x)
+ want := T24{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [24]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t24copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T25 struct {
+ pre [8]byte
+ mid [25]byte
+ post [8]byte
+}
+
+//go:noinline
+func t25copy_ssa(y, x *[25]byte) {
+ *y = *x
+}
+func testCopy25(t *testing.T) {
+ a := T25{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [25]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [25]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124}
+ t25copy_ssa(&a.mid, &x)
+ want := T25{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [25]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t25copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T31 struct {
+ pre [8]byte
+ mid [31]byte
+ post [8]byte
+}
+
+//go:noinline
+func t31copy_ssa(y, x *[31]byte) {
+ *y = *x
+}
+func testCopy31(t *testing.T) {
+ a := T31{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [31]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [31]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130}
+ t31copy_ssa(&a.mid, &x)
+ want := T31{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [31]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t31copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T32 struct {
+ pre [8]byte
+ mid [32]byte
+ post [8]byte
+}
+
+//go:noinline
+func t32copy_ssa(y, x *[32]byte) {
+ *y = *x
+}
+func testCopy32(t *testing.T) {
+ a := T32{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [32]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [32]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131}
+ t32copy_ssa(&a.mid, &x)
+ want := T32{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [32]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t32copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T33 struct {
+ pre [8]byte
+ mid [33]byte
+ post [8]byte
+}
+
+//go:noinline
+func t33copy_ssa(y, x *[33]byte) {
+ *y = *x
+}
+func testCopy33(t *testing.T) {
+ a := T33{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [33]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [33]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}
+ t33copy_ssa(&a.mid, &x)
+ want := T33{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [33]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t33copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T63 struct {
+ pre [8]byte
+ mid [63]byte
+ post [8]byte
+}
+
+//go:noinline
+func t63copy_ssa(y, x *[63]byte) {
+ *y = *x
+}
+func testCopy63(t *testing.T) {
+ a := T63{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [63]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [63]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162}
+ t63copy_ssa(&a.mid, &x)
+ want := T63{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [63]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t63copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T64 struct {
+ pre [8]byte
+ mid [64]byte
+ post [8]byte
+}
+
+//go:noinline
+func t64copy_ssa(y, x *[64]byte) {
+ *y = *x
+}
+func testCopy64(t *testing.T) {
+ a := T64{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [64]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [64]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163}
+ t64copy_ssa(&a.mid, &x)
+ want := T64{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [64]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t64copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T65 struct {
+ pre [8]byte
+ mid [65]byte
+ post [8]byte
+}
+
+//go:noinline
+func t65copy_ssa(y, x *[65]byte) {
+ *y = *x
+}
+func testCopy65(t *testing.T) {
+ a := T65{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [65]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [65]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164}
+ t65copy_ssa(&a.mid, &x)
+ want := T65{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [65]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t65copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1023 struct {
+ pre [8]byte
+ mid [1023]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1023copy_ssa(y, x *[1023]byte) {
+ *y = *x
+}
+func testCopy1023(t *testing.T) {
+ a := T1023{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1023]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1023]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}
+ t1023copy_ssa(&a.mid, &x)
+ want := T1023{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1023]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1023copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1024 struct {
+ pre [8]byte
+ mid [1024]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1024copy_ssa(y, x *[1024]byte) {
+ *y = *x
+}
+func testCopy1024(t *testing.T) {
+ a := T1024{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1024]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1024]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123}
+ t1024copy_ssa(&a.mid, &x)
+ want := T1024{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1024]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1024copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1025 struct {
+ pre [8]byte
+ mid [1025]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1025copy_ssa(y, x *[1025]byte) {
+ *y = *x
+}
+func testCopy1025(t *testing.T) {
+ a := T1025{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1025]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1025]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124}
+ t1025copy_ssa(&a.mid, &x)
+ want := T1025{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1025]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1025copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1031 struct {
+ pre [8]byte
+ mid [1031]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1031copy_ssa(y, x *[1031]byte) {
+ *y = *x
+}
+func testCopy1031(t *testing.T) {
+ a := T1031{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1031]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1031]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130}
+ t1031copy_ssa(&a.mid, &x)
+ want := T1031{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1031]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1031copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1032 struct {
+ pre [8]byte
+ mid [1032]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1032copy_ssa(y, x *[1032]byte) {
+ *y = *x
+}
+func testCopy1032(t *testing.T) {
+ a := T1032{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1032]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1032]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131}
+ t1032copy_ssa(&a.mid, &x)
+ want := T1032{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1032]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1032copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1033 struct {
+ pre [8]byte
+ mid [1033]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1033copy_ssa(y, x *[1033]byte) {
+ *y = *x
+}
+func testCopy1033(t *testing.T) {
+ a := T1033{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1033]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1033]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}
+ t1033copy_ssa(&a.mid, &x)
+ want := T1033{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1033]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1033copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1039 struct {
+ pre [8]byte
+ mid [1039]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1039copy_ssa(y, x *[1039]byte) {
+ *y = *x
+}
+func testCopy1039(t *testing.T) {
+ a := T1039{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1039]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 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}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1039]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138}
+ t1039copy_ssa(&a.mid, &x)
+ want := T1039{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1039]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1039copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1040 struct {
+ pre [8]byte
+ mid [1040]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1040copy_ssa(y, x *[1040]byte) {
+ *y = *x
+}
+func testCopy1040(t *testing.T) {
+ a := T1040{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1040]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 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}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1040]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139}
+ t1040copy_ssa(&a.mid, &x)
+ want := T1040{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1040]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1040copy got=%v, want %v\n", a, want)
+ }
+}
+
+type T1041 struct {
+ pre [8]byte
+ mid [1041]byte
+ post [8]byte
+}
+
+//go:noinline
+func t1041copy_ssa(y, x *[1041]byte) {
+ *y = *x
+}
+func testCopy1041(t *testing.T) {
+ a := T1041{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1041]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 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}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ x := [1041]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140}
+ t1041copy_ssa(&a.mid, &x)
+ want := T1041{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1041]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+ if a != want {
+ t.Errorf("t1041copy got=%v, want %v\n", a, want)
+ }
+}
+
+//go:noinline
+func tu2copy_ssa(docopy bool, data [2]byte, x *[2]byte) {
+ if docopy {
+ *x = data
+ }
+}
+func testUnalignedCopy2(t *testing.T) {
+ var a [2]byte
+ t2 := [2]byte{2, 3}
+ tu2copy_ssa(true, t2, &a)
+ want2 := [2]byte{2, 3}
+ if a != want2 {
+ t.Errorf("tu2copy got=%v, want %v\n", a, want2)
+ }
+}
+
+//go:noinline
+func tu3copy_ssa(docopy bool, data [3]byte, x *[3]byte) {
+ if docopy {
+ *x = data
+ }
+}
+func testUnalignedCopy3(t *testing.T) {
+ var a [3]byte
+ t3 := [3]byte{3, 4, 5}
+ tu3copy_ssa(true, t3, &a)
+ want3 := [3]byte{3, 4, 5}
+ if a != want3 {
+ t.Errorf("tu3copy got=%v, want %v\n", a, want3)
+ }
+}
+
+//go:noinline
+func tu4copy_ssa(docopy bool, data [4]byte, x *[4]byte) {
+ if docopy {
+ *x = data
+ }
+}
+func testUnalignedCopy4(t *testing.T) {
+ var a [4]byte
+ t4 := [4]byte{4, 5, 6, 7}
+ tu4copy_ssa(true, t4, &a)
+ want4 := [4]byte{4, 5, 6, 7}
+ if a != want4 {
+ t.Errorf("tu4copy got=%v, want %v\n", a, want4)
+ }
+}
+
+//go:noinline
+func tu5copy_ssa(docopy bool, data [5]byte, x *[5]byte) {
+ if docopy {
+ *x = data
+ }
+}
+func testUnalignedCopy5(t *testing.T) {
+ var a [5]byte
+ t5 := [5]byte{5, 6, 7, 8, 9}
+ tu5copy_ssa(true, t5, &a)
+ want5 := [5]byte{5, 6, 7, 8, 9}
+ if a != want5 {
+ t.Errorf("tu5copy got=%v, want %v\n", a, want5)
+ }
+}
+
+//go:noinline
+func tu6copy_ssa(docopy bool, data [6]byte, x *[6]byte) {
+ if docopy {
+ *x = data
+ }
+}
+func testUnalignedCopy6(t *testing.T) {
+ var a [6]byte
+ t6 := [6]byte{6, 7, 8, 9, 10, 11}
+ tu6copy_ssa(true, t6, &a)
+ want6 := [6]byte{6, 7, 8, 9, 10, 11}
+ if a != want6 {
+ t.Errorf("tu6copy got=%v, want %v\n", a, want6)
+ }
+}
+
+//go:noinline
+func tu7copy_ssa(docopy bool, data [7]byte, x *[7]byte) {
+ if docopy {
+ *x = data
+ }
+}
+func testUnalignedCopy7(t *testing.T) {
+ var a [7]byte
+ t7 := [7]byte{7, 8, 9, 10, 11, 12, 13}
+ tu7copy_ssa(true, t7, &a)
+ want7 := [7]byte{7, 8, 9, 10, 11, 12, 13}
+ if a != want7 {
+ t.Errorf("tu7copy got=%v, want %v\n", a, want7)
+ }
+}
+func TestCopy(t *testing.T) {
+ testCopy1(t)
+ testCopy2(t)
+ testCopy3(t)
+ testCopy4(t)
+ testCopy5(t)
+ testCopy6(t)
+ testCopy7(t)
+ testCopy8(t)
+ testCopy9(t)
+ testCopy10(t)
+ testCopy15(t)
+ testCopy16(t)
+ testCopy17(t)
+ testCopy23(t)
+ testCopy24(t)
+ testCopy25(t)
+ testCopy31(t)
+ testCopy32(t)
+ testCopy33(t)
+ testCopy63(t)
+ testCopy64(t)
+ testCopy65(t)
+ testCopy1023(t)
+ testCopy1024(t)
+ testCopy1025(t)
+ testCopy1031(t)
+ testCopy1032(t)
+ testCopy1033(t)
+ testCopy1039(t)
+ testCopy1040(t)
+ testCopy1041(t)
+ testUnalignedCopy2(t)
+ testUnalignedCopy3(t)
+ testUnalignedCopy4(t)
+ testUnalignedCopy5(t)
+ testUnalignedCopy6(t)
+ testUnalignedCopy7(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/ctl_test.go b/src/cmd/compile/internal/gc/testdata/ctl_test.go
new file mode 100644
index 0000000..16d571c
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/ctl_test.go
@@ -0,0 +1,149 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test control flow
+
+package main
+
+import "testing"
+
+// nor_ssa calculates NOR(a, b).
+// It is implemented in a way that generates
+// phi control values.
+func nor_ssa(a, b bool) bool {
+ var c bool
+ if a {
+ c = true
+ }
+ if b {
+ c = true
+ }
+ if c {
+ return false
+ }
+ return true
+}
+
+func testPhiControl(t *testing.T) {
+ tests := [...][3]bool{ // a, b, want
+ {false, false, true},
+ {true, false, false},
+ {false, true, false},
+ {true, true, false},
+ }
+ for _, test := range tests {
+ a, b := test[0], test[1]
+ got := nor_ssa(a, b)
+ want := test[2]
+ if want != got {
+ t.Errorf("nor(%t, %t)=%t got %t", a, b, want, got)
+ }
+ }
+}
+
+func emptyRange_ssa(b []byte) bool {
+ for _, x := range b {
+ _ = x
+ }
+ return true
+}
+
+func testEmptyRange(t *testing.T) {
+ if !emptyRange_ssa([]byte{}) {
+ t.Errorf("emptyRange_ssa([]byte{})=false, want true")
+ }
+}
+
+func switch_ssa(a int) int {
+ ret := 0
+ switch a {
+ case 5:
+ ret += 5
+ case 4:
+ ret += 4
+ case 3:
+ ret += 3
+ case 2:
+ ret += 2
+ case 1:
+ ret += 1
+ }
+ return ret
+
+}
+
+func fallthrough_ssa(a int) int {
+ ret := 0
+ switch a {
+ case 5:
+ ret++
+ fallthrough
+ case 4:
+ ret++
+ fallthrough
+ case 3:
+ ret++
+ fallthrough
+ case 2:
+ ret++
+ fallthrough
+ case 1:
+ ret++
+ }
+ return ret
+
+}
+
+func testFallthrough(t *testing.T) {
+ for i := 0; i < 6; i++ {
+ if got := fallthrough_ssa(i); got != i {
+ t.Errorf("fallthrough_ssa(i) = %d, wanted %d", got, i)
+ }
+ }
+}
+
+func testSwitch(t *testing.T) {
+ for i := 0; i < 6; i++ {
+ if got := switch_ssa(i); got != i {
+ t.Errorf("switch_ssa(i) = %d, wanted %d", got, i)
+ }
+ }
+}
+
+type junk struct {
+ step int
+}
+
+// flagOverwrite_ssa is intended to reproduce an issue seen where a XOR
+// was scheduled between a compare and branch, clearing flags.
+//go:noinline
+func flagOverwrite_ssa(s *junk, c int) int {
+ if '0' <= c && c <= '9' {
+ s.step = 0
+ return 1
+ }
+ if c == 'e' || c == 'E' {
+ s.step = 0
+ return 2
+ }
+ s.step = 0
+ return 3
+}
+
+func testFlagOverwrite(t *testing.T) {
+ j := junk{}
+ if got := flagOverwrite_ssa(&j, ' '); got != 3 {
+ t.Errorf("flagOverwrite_ssa = %d, wanted 3", got)
+ }
+}
+
+func TestCtl(t *testing.T) {
+ testPhiControl(t)
+ testEmptyRange(t)
+
+ testSwitch(t)
+ testFallthrough(t)
+
+ testFlagOverwrite(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/deferNoReturn_test.go b/src/cmd/compile/internal/gc/testdata/deferNoReturn_test.go
new file mode 100644
index 0000000..308e897
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/deferNoReturn_test.go
@@ -0,0 +1,21 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that a defer in a function with no return
+// statement will compile correctly.
+
+package main
+
+import "testing"
+
+func deferNoReturn_ssa() {
+ defer func() { println("returned") }()
+ for {
+ println("loop")
+ }
+}
+
+func TestDeferNoReturn(t *testing.T) {
+ // This is a compile-time test, no runtime testing required.
+}
diff --git a/src/cmd/compile/internal/gc/testdata/divbyzero_test.go b/src/cmd/compile/internal/gc/testdata/divbyzero_test.go
new file mode 100644
index 0000000..ee848b3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/divbyzero_test.go
@@ -0,0 +1,48 @@
+package main
+
+import (
+ "runtime"
+ "testing"
+)
+
+func checkDivByZero(f func()) (divByZero bool) {
+ defer func() {
+ if r := recover(); r != nil {
+ if e, ok := r.(runtime.Error); ok && e.Error() == "runtime error: integer divide by zero" {
+ divByZero = true
+ }
+ }
+ }()
+ f()
+ return false
+}
+
+//go:noinline
+func div_a(i uint, s []int) int {
+ return s[i%uint(len(s))]
+}
+
+//go:noinline
+func div_b(i uint, j uint) uint {
+ return i / j
+}
+
+//go:noinline
+func div_c(i int) int {
+ return 7 / (i - i)
+}
+
+func TestDivByZero(t *testing.T) {
+ if got := checkDivByZero(func() { div_b(7, 0) }); !got {
+ t.Errorf("expected div by zero for b(7, 0), got no error\n")
+ }
+ if got := checkDivByZero(func() { div_b(7, 7) }); got {
+ t.Errorf("expected no error for b(7, 7), got div by zero\n")
+ }
+ if got := checkDivByZero(func() { div_a(4, nil) }); !got {
+ t.Errorf("expected div by zero for a(4, nil), got no error\n")
+ }
+ if got := checkDivByZero(func() { div_c(5) }); !got {
+ t.Errorf("expected div by zero for c(5), got no error\n")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/dupLoad_test.go b/src/cmd/compile/internal/gc/testdata/dupLoad_test.go
new file mode 100644
index 0000000..d859123
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/dupLoad_test.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test makes sure that we don't split a single
+// load up into two separate loads.
+
+package main
+
+import "testing"
+
+//go:noinline
+func read1(b []byte) (uint16, uint16) {
+ // There is only a single read of b[0]. The two
+ // returned values must have the same low byte.
+ v := b[0]
+ return uint16(v), uint16(v) | uint16(b[1])<<8
+}
+
+func main1(t *testing.T) {
+ const N = 100000
+ done := make(chan bool, 2)
+ b := make([]byte, 2)
+ go func() {
+ for i := 0; i < N; i++ {
+ b[0] = byte(i)
+ b[1] = byte(i)
+ }
+ done <- true
+ }()
+ go func() {
+ for i := 0; i < N; i++ {
+ x, y := read1(b)
+ if byte(x) != byte(y) {
+ t.Errorf("x=%x y=%x\n", x, y)
+ done <- false
+ return
+ }
+ }
+ done <- true
+ }()
+ <-done
+ <-done
+}
+
+//go:noinline
+func read2(b []byte) (uint16, uint16) {
+ // There is only a single read of b[1]. The two
+ // returned values must have the same high byte.
+ v := uint16(b[1]) << 8
+ return v, uint16(b[0]) | v
+}
+
+func main2(t *testing.T) {
+ const N = 100000
+ done := make(chan bool, 2)
+ b := make([]byte, 2)
+ go func() {
+ for i := 0; i < N; i++ {
+ b[0] = byte(i)
+ b[1] = byte(i)
+ }
+ done <- true
+ }()
+ go func() {
+ for i := 0; i < N; i++ {
+ x, y := read2(b)
+ if x&0xff00 != y&0xff00 {
+ t.Errorf("x=%x y=%x\n", x, y)
+ done <- false
+ return
+ }
+ }
+ done <- true
+ }()
+ <-done
+ <-done
+}
+
+func TestDupLoad(t *testing.T) {
+ main1(t)
+ main2(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/flowgraph_generator1.go b/src/cmd/compile/internal/gc/testdata/flowgraph_generator1.go
new file mode 100644
index 0000000..ad22601
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/flowgraph_generator1.go
@@ -0,0 +1,315 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "strings"
+)
+
+// make fake flow graph.
+
+// The blocks of the flow graph are designated with letters A
+// through Z, always including A (start block) and Z (exit
+// block) The specification of a flow graph is a comma-
+// separated list of block successor words, for blocks ordered
+// A, B, C etc, where each block except Z has one or two
+// successors, and any block except A can be a target. Within
+// the generated code, each block with two successors includes
+// a conditional testing x & 1 != 0 (x is the input parameter
+// to the generated function) and also unconditionally shifts x
+// right by one, so that different inputs generate different
+// execution paths, including loops. Every block inverts a
+// global binary to ensure it is not empty. For a flow graph
+// with J words (J+1 blocks), a J-1 bit serial number specifies
+// which blocks (not including A and Z) include an increment of
+// the return variable y by increasing powers of 10, and a
+// different version of the test function is created for each
+// of the 2-to-the-(J-1) serial numbers.
+
+// For each generated function a compact summary is also
+// created so that the generated function can be simulated
+// with a simple interpreter to sanity check the behavior of
+// the compiled code.
+
+// For example:
+
+// func BC_CD_BE_BZ_CZ101(x int64) int64 {
+// y := int64(0)
+// var b int64
+// _ = b
+// b = x & 1
+// x = x >> 1
+// if b != 0 {
+// goto C
+// }
+// goto B
+// B:
+// glob_ = !glob_
+// y += 1
+// b = x & 1
+// x = x >> 1
+// if b != 0 {
+// goto D
+// }
+// goto C
+// C:
+// glob_ = !glob_
+// // no y increment
+// b = x & 1
+// x = x >> 1
+// if b != 0 {
+// goto E
+// }
+// goto B
+// D:
+// glob_ = !glob_
+// y += 10
+// b = x & 1
+// x = x >> 1
+// if b != 0 {
+// goto Z
+// }
+// goto B
+// E:
+// glob_ = !glob_
+// // no y increment
+// b = x & 1
+// x = x >> 1
+// if b != 0 {
+// goto Z
+// }
+// goto C
+// Z:
+// return y
+// }
+
+// {f:BC_CD_BE_BZ_CZ101,
+// maxin:32, blocks:[]blo{
+// blo{inc:0, cond:true, succs:[2]int64{1, 2}},
+// blo{inc:1, cond:true, succs:[2]int64{2, 3}},
+// blo{inc:0, cond:true, succs:[2]int64{1, 4}},
+// blo{inc:10, cond:true, succs:[2]int64{1, 25}},
+// blo{inc:0, cond:true, succs:[2]int64{2, 25}},}},
+
+var labels string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+func blocks(spec string) (blocks []string, fnameBase string) {
+ spec = strings.ToUpper(spec)
+ blocks = strings.Split(spec, ",")
+ fnameBase = strings.Replace(spec, ",", "_", -1)
+ return
+}
+
+func makeFunctionFromFlowGraph(blocks []blo, fname string) string {
+ s := ""
+
+ for j := range blocks {
+ // begin block
+ if j == 0 {
+ // block A, implicit label
+ s += `
+func ` + fname + `(x int64) int64 {
+ y := int64(0)
+ var b int64
+ _ = b`
+ } else {
+ // block B,C, etc, explicit label w/ conditional increment
+ l := labels[j : j+1]
+ yeq := `
+ // no y increment`
+ if blocks[j].inc != 0 {
+ yeq = `
+ y += ` + fmt.Sprintf("%d", blocks[j].inc)
+ }
+
+ s += `
+` + l + `:
+ glob = !glob` + yeq
+ }
+
+ // edges to successors
+ if blocks[j].cond { // conditionally branch to second successor
+ s += `
+ b = x & 1
+ x = x >> 1
+ if b != 0 {` + `
+ goto ` + string(labels[blocks[j].succs[1]]) + `
+ }`
+
+ }
+ // branch to first successor
+ s += `
+ goto ` + string(labels[blocks[j].succs[0]])
+ }
+
+ // end block (Z)
+ s += `
+Z:
+ return y
+}
+`
+ return s
+}
+
+var graphs []string = []string{
+ "Z", "BZ,Z", "B,BZ", "BZ,BZ",
+ "ZB,Z", "B,ZB", "ZB,BZ", "ZB,ZB",
+
+ "BC,C,Z", "BC,BC,Z", "BC,BC,BZ",
+ "BC,Z,Z", "BC,ZC,Z", "BC,ZC,BZ",
+ "BZ,C,Z", "BZ,BC,Z", "BZ,CZ,Z",
+ "BZ,C,BZ", "BZ,BC,BZ", "BZ,CZ,BZ",
+ "BZ,C,CZ", "BZ,BC,CZ", "BZ,CZ,CZ",
+
+ "BC,CD,BE,BZ,CZ",
+ "BC,BD,CE,CZ,BZ",
+ "BC,BD,CE,FZ,GZ,F,G",
+ "BC,BD,CE,FZ,GZ,G,F",
+
+ "BC,DE,BE,FZ,FZ,Z",
+ "BC,DE,BE,FZ,ZF,Z",
+ "BC,DE,BE,ZF,FZ,Z",
+ "BC,DE,EB,FZ,FZ,Z",
+ "BC,ED,BE,FZ,FZ,Z",
+ "CB,DE,BE,FZ,FZ,Z",
+
+ "CB,ED,BE,FZ,FZ,Z",
+ "BC,ED,EB,FZ,ZF,Z",
+ "CB,DE,EB,ZF,FZ,Z",
+ "CB,ED,EB,FZ,FZ,Z",
+
+ "BZ,CD,CD,CE,BZ",
+ "EC,DF,FG,ZC,GB,BE,FD",
+ "BH,CF,DG,HE,BF,CG,DH,BZ",
+}
+
+// blo describes a block in the generated/interpreted code
+type blo struct {
+ inc int64 // increment amount
+ cond bool // block ends in conditional
+ succs [2]int64
+}
+
+// strings2blocks converts a slice of strings specifying
+// successors into a slice of blo encoding the blocks in a
+// common form easy to execute or interpret.
+func strings2blocks(blocks []string, fname string, i int) (bs []blo, cond uint) {
+ bs = make([]blo, len(blocks))
+ edge := int64(1)
+ cond = 0
+ k := uint(0)
+ for j, s := range blocks {
+ if j == 0 {
+ } else {
+ if (i>>k)&1 != 0 {
+ bs[j].inc = edge
+ edge *= 10
+ }
+ k++
+ }
+ if len(s) > 1 {
+ bs[j].succs[1] = int64(blocks[j][1] - 'A')
+ bs[j].cond = true
+ cond++
+ }
+ bs[j].succs[0] = int64(blocks[j][0] - 'A')
+ }
+ return bs, cond
+}
+
+// fmtBlocks writes out the blocks for consumption in the generated test
+func fmtBlocks(bs []blo) string {
+ s := "[]blo{"
+ for _, b := range bs {
+ s += fmt.Sprintf("blo{inc:%d, cond:%v, succs:[2]int64{%d, %d}},", b.inc, b.cond, b.succs[0], b.succs[1])
+ }
+ s += "}"
+ return s
+}
+
+func main() {
+ fmt.Printf(`// This is a machine-generated test file from flowgraph_generator1.go.
+package main
+import "fmt"
+var glob bool
+`)
+ s := "var funs []fun = []fun{"
+ for _, g := range graphs {
+ split, fnameBase := blocks(g)
+ nconfigs := 1 << uint(len(split)-1)
+
+ for i := 0; i < nconfigs; i++ {
+ fname := fnameBase + fmt.Sprintf("%b", i)
+ bs, k := strings2blocks(split, fname, i)
+ fmt.Printf("%s", makeFunctionFromFlowGraph(bs, fname))
+ s += `
+ {f:` + fname + `, maxin:` + fmt.Sprintf("%d", 1<<k) + `, blocks:` + fmtBlocks(bs) + `},`
+ }
+
+ }
+ s += `}
+`
+ // write types for name+array tables.
+ fmt.Printf("%s",
+ `
+type blo struct {
+ inc int64
+ cond bool
+ succs [2]int64
+}
+type fun struct {
+ f func(int64) int64
+ maxin int64
+ blocks []blo
+}
+`)
+ // write table of function names and blo arrays.
+ fmt.Printf("%s", s)
+
+ // write interpreter and main/test
+ fmt.Printf("%s", `
+func interpret(blocks []blo, x int64) (int64, bool) {
+ y := int64(0)
+ last := int64(25) // 'Z'-'A'
+ j := int64(0)
+ for i := 0; i < 4*len(blocks); i++ {
+ b := blocks[j]
+ y += b.inc
+ next := b.succs[0]
+ if b.cond {
+ c := x&1 != 0
+ x = x>>1
+ if c {
+ next = b.succs[1]
+ }
+ }
+ if next == last {
+ return y, true
+ }
+ j = next
+ }
+ return -1, false
+}
+
+func main() {
+ sum := int64(0)
+ for i, f := range funs {
+ for x := int64(0); x < 16*f.maxin; x++ {
+ y, ok := interpret(f.blocks, x)
+ if ok {
+ yy := f.f(x)
+ if y != yy {
+ fmt.Printf("y(%d) != yy(%d), x=%b, i=%d, blocks=%v\n", y, yy, x, i, f.blocks)
+ return
+ }
+ sum += y
+ }
+ }
+ }
+// fmt.Printf("Sum of all returns over all terminating inputs is %d\n", sum)
+}
+`)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/fp_test.go b/src/cmd/compile/internal/gc/testdata/fp_test.go
new file mode 100644
index 0000000..7d61a80
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/fp_test.go
@@ -0,0 +1,1773 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests floating point arithmetic expressions
+
+package main
+
+import (
+ "fmt"
+ "testing"
+)
+
+// manysub_ssa is designed to tickle bugs that depend on register
+// pressure or unfriendly operand ordering in registers (and at
+// least once it succeeded in this).
+//go:noinline
+func manysub_ssa(a, b, c, d float64) (aa, ab, ac, ad, ba, bb, bc, bd, ca, cb, cc, cd, da, db, dc, dd float64) {
+ aa = a + 11.0 - a
+ ab = a - b
+ ac = a - c
+ ad = a - d
+ ba = b - a
+ bb = b + 22.0 - b
+ bc = b - c
+ bd = b - d
+ ca = c - a
+ cb = c - b
+ cc = c + 33.0 - c
+ cd = c - d
+ da = d - a
+ db = d - b
+ dc = d - c
+ dd = d + 44.0 - d
+ return
+}
+
+// fpspill_ssa attempts to trigger a bug where phis with floating point values
+// were stored in non-fp registers causing an error in doasm.
+//go:noinline
+func fpspill_ssa(a int) float64 {
+
+ ret := -1.0
+ switch a {
+ case 0:
+ ret = 1.0
+ case 1:
+ ret = 1.1
+ case 2:
+ ret = 1.2
+ case 3:
+ ret = 1.3
+ case 4:
+ ret = 1.4
+ case 5:
+ ret = 1.5
+ case 6:
+ ret = 1.6
+ case 7:
+ ret = 1.7
+ case 8:
+ ret = 1.8
+ case 9:
+ ret = 1.9
+ case 10:
+ ret = 1.10
+ case 11:
+ ret = 1.11
+ case 12:
+ ret = 1.12
+ case 13:
+ ret = 1.13
+ case 14:
+ ret = 1.14
+ case 15:
+ ret = 1.15
+ case 16:
+ ret = 1.16
+ }
+ return ret
+}
+
+//go:noinline
+func add64_ssa(a, b float64) float64 {
+ return a + b
+}
+
+//go:noinline
+func mul64_ssa(a, b float64) float64 {
+ return a * b
+}
+
+//go:noinline
+func sub64_ssa(a, b float64) float64 {
+ return a - b
+}
+
+//go:noinline
+func div64_ssa(a, b float64) float64 {
+ return a / b
+}
+
+//go:noinline
+func neg64_ssa(a, b float64) float64 {
+ return -a + -1*b
+}
+
+//go:noinline
+func add32_ssa(a, b float32) float32 {
+ return a + b
+}
+
+//go:noinline
+func mul32_ssa(a, b float32) float32 {
+ return a * b
+}
+
+//go:noinline
+func sub32_ssa(a, b float32) float32 {
+ return a - b
+}
+
+//go:noinline
+func div32_ssa(a, b float32) float32 {
+ return a / b
+}
+
+//go:noinline
+func neg32_ssa(a, b float32) float32 {
+ return -a + -1*b
+}
+
+//go:noinline
+func conv2Float64_ssa(a int8, b uint8, c int16, d uint16,
+ e int32, f uint32, g int64, h uint64, i float32) (aa, bb, cc, dd, ee, ff, gg, hh, ii float64) {
+ aa = float64(a)
+ bb = float64(b)
+ cc = float64(c)
+ hh = float64(h)
+ dd = float64(d)
+ ee = float64(e)
+ ff = float64(f)
+ gg = float64(g)
+ ii = float64(i)
+ return
+}
+
+//go:noinline
+func conv2Float32_ssa(a int8, b uint8, c int16, d uint16,
+ e int32, f uint32, g int64, h uint64, i float64) (aa, bb, cc, dd, ee, ff, gg, hh, ii float32) {
+ aa = float32(a)
+ bb = float32(b)
+ cc = float32(c)
+ dd = float32(d)
+ ee = float32(e)
+ ff = float32(f)
+ gg = float32(g)
+ hh = float32(h)
+ ii = float32(i)
+ return
+}
+
+func integer2floatConversions(t *testing.T) {
+ {
+ a, b, c, d, e, f, g, h, i := conv2Float64_ssa(0, 0, 0, 0, 0, 0, 0, 0, 0)
+ expectAll64(t, "zero64", 0, a, b, c, d, e, f, g, h, i)
+ }
+ {
+ a, b, c, d, e, f, g, h, i := conv2Float64_ssa(1, 1, 1, 1, 1, 1, 1, 1, 1)
+ expectAll64(t, "one64", 1, a, b, c, d, e, f, g, h, i)
+ }
+ {
+ a, b, c, d, e, f, g, h, i := conv2Float32_ssa(0, 0, 0, 0, 0, 0, 0, 0, 0)
+ expectAll32(t, "zero32", 0, a, b, c, d, e, f, g, h, i)
+ }
+ {
+ a, b, c, d, e, f, g, h, i := conv2Float32_ssa(1, 1, 1, 1, 1, 1, 1, 1, 1)
+ expectAll32(t, "one32", 1, a, b, c, d, e, f, g, h, i)
+ }
+ {
+ // Check maximum values
+ a, b, c, d, e, f, g, h, i := conv2Float64_ssa(127, 255, 32767, 65535, 0x7fffffff, 0xffffffff, 0x7fffFFFFffffFFFF, 0xffffFFFFffffFFFF, 3.402823e38)
+ expect64(t, "a", a, 127)
+ expect64(t, "b", b, 255)
+ expect64(t, "c", c, 32767)
+ expect64(t, "d", d, 65535)
+ expect64(t, "e", e, float64(int32(0x7fffffff)))
+ expect64(t, "f", f, float64(uint32(0xffffffff)))
+ expect64(t, "g", g, float64(int64(0x7fffffffffffffff)))
+ expect64(t, "h", h, float64(uint64(0xffffffffffffffff)))
+ expect64(t, "i", i, float64(float32(3.402823e38)))
+ }
+ {
+ // Check minimum values (and tweaks for unsigned)
+ a, b, c, d, e, f, g, h, i := conv2Float64_ssa(-128, 254, -32768, 65534, ^0x7fffffff, 0xfffffffe, ^0x7fffFFFFffffFFFF, 0xffffFFFFffffF401, 1.5e-45)
+ expect64(t, "a", a, -128)
+ expect64(t, "b", b, 254)
+ expect64(t, "c", c, -32768)
+ expect64(t, "d", d, 65534)
+ expect64(t, "e", e, float64(^int32(0x7fffffff)))
+ expect64(t, "f", f, float64(uint32(0xfffffffe)))
+ expect64(t, "g", g, float64(^int64(0x7fffffffffffffff)))
+ expect64(t, "h", h, float64(uint64(0xfffffffffffff401)))
+ expect64(t, "i", i, float64(float32(1.5e-45)))
+ }
+ {
+ // Check maximum values
+ a, b, c, d, e, f, g, h, i := conv2Float32_ssa(127, 255, 32767, 65535, 0x7fffffff, 0xffffffff, 0x7fffFFFFffffFFFF, 0xffffFFFFffffFFFF, 3.402823e38)
+ expect32(t, "a", a, 127)
+ expect32(t, "b", b, 255)
+ expect32(t, "c", c, 32767)
+ expect32(t, "d", d, 65535)
+ expect32(t, "e", e, float32(int32(0x7fffffff)))
+ expect32(t, "f", f, float32(uint32(0xffffffff)))
+ expect32(t, "g", g, float32(int64(0x7fffffffffffffff)))
+ expect32(t, "h", h, float32(uint64(0xffffffffffffffff)))
+ expect32(t, "i", i, float32(float64(3.402823e38)))
+ }
+ {
+ // Check minimum values (and tweaks for unsigned)
+ a, b, c, d, e, f, g, h, i := conv2Float32_ssa(-128, 254, -32768, 65534, ^0x7fffffff, 0xfffffffe, ^0x7fffFFFFffffFFFF, 0xffffFFFFffffF401, 1.5e-45)
+ expect32(t, "a", a, -128)
+ expect32(t, "b", b, 254)
+ expect32(t, "c", c, -32768)
+ expect32(t, "d", d, 65534)
+ expect32(t, "e", e, float32(^int32(0x7fffffff)))
+ expect32(t, "f", f, float32(uint32(0xfffffffe)))
+ expect32(t, "g", g, float32(^int64(0x7fffffffffffffff)))
+ expect32(t, "h", h, float32(uint64(0xfffffffffffff401)))
+ expect32(t, "i", i, float32(float64(1.5e-45)))
+ }
+}
+
+func multiplyAdd(t *testing.T) {
+ {
+ // Test that a multiply-accumulate operation with intermediate
+ // rounding forced by a float32() cast produces the expected
+ // result.
+ // Test cases generated experimentally on a system (s390x) that
+ // supports fused multiply-add instructions.
+ var tests = [...]struct{ x, y, z, res float32 }{
+ {0.6046603, 0.9405091, 0.6645601, 1.2332485}, // fused multiply-add result: 1.2332486
+ {0.67908466, 0.21855305, 0.20318687, 0.3516029}, // fused multiply-add result: 0.35160288
+ {0.29311424, 0.29708257, 0.752573, 0.8396522}, // fused multiply-add result: 0.8396521
+ {0.5305857, 0.2535405, 0.282081, 0.41660595}, // fused multiply-add result: 0.41660598
+ {0.29711226, 0.89436173, 0.097454615, 0.36318043}, // fused multiply-add result: 0.36318046
+ {0.6810783, 0.24151509, 0.31152245, 0.47601312}, // fused multiply-add result: 0.47601315
+ {0.73023146, 0.18292491, 0.4283571, 0.5619346}, // fused multiply-add result: 0.56193465
+ {0.89634174, 0.32208398, 0.7211478, 1.009845}, // fused multiply-add result: 1.0098451
+ {0.6280982, 0.12675293, 0.2813303, 0.36094356}, // fused multiply-add result: 0.3609436
+ {0.29400632, 0.75316125, 0.15096405, 0.3723982}, // fused multiply-add result: 0.37239823
+ }
+ check := func(s string, got, expected float32) {
+ if got != expected {
+ fmt.Printf("multiplyAdd: %s, expected %g, got %g\n", s, expected, got)
+ }
+ }
+ for _, t := range tests {
+ check(
+ fmt.Sprintf("float32(%v * %v) + %v", t.x, t.y, t.z),
+ func(x, y, z float32) float32 {
+ return float32(x*y) + z
+ }(t.x, t.y, t.z),
+ t.res)
+
+ check(
+ fmt.Sprintf("%v += float32(%v * %v)", t.z, t.x, t.y),
+ func(x, y, z float32) float32 {
+ z += float32(x * y)
+ return z
+ }(t.x, t.y, t.z),
+ t.res)
+ }
+ }
+ {
+ // Test that a multiply-accumulate operation with intermediate
+ // rounding forced by a float64() cast produces the expected
+ // result.
+ // Test cases generated experimentally on a system (s390x) that
+ // supports fused multiply-add instructions.
+ var tests = [...]struct{ x, y, z, res float64 }{
+ {0.4688898449024232, 0.28303415118044517, 0.29310185733681576, 0.42581369658590373}, // fused multiply-add result: 0.4258136965859037
+ {0.7886049150193449, 0.3618054804803169, 0.8805431227416171, 1.1658647029293308}, // fused multiply-add result: 1.1658647029293305
+ {0.7302314772948083, 0.18292491645390843, 0.4283570818068078, 0.5619346137829748}, // fused multiply-add result: 0.5619346137829747
+ {0.6908388315056789, 0.7109071952999951, 0.5637795958152644, 1.0549018919252924}, // fused multiply-add result: 1.0549018919252926
+ {0.4584424785756506, 0.6001655953233308, 0.02626515060968944, 0.3014065536855481}, // fused multiply-add result: 0.30140655368554814
+ {0.539210105890946, 0.9756748149873165, 0.7507630564795985, 1.2768567767840384}, // fused multiply-add result: 1.2768567767840386
+ {0.7830349733960021, 0.3932509992288867, 0.1304138461737918, 0.4383431318929343}, // fused multiply-add result: 0.43834313189293433
+ {0.6841751300974551, 0.6530402051353608, 0.524499759549865, 0.9712936268572192}, // fused multiply-add result: 0.9712936268572193
+ {0.3691117091643448, 0.826454125634742, 0.34768170859156955, 0.6527356034505334}, // fused multiply-add result: 0.6527356034505333
+ {0.16867966833433606, 0.33136826030698385, 0.8279280961505588, 0.8838231843956668}, // fused multiply-add result: 0.8838231843956669
+ }
+ check := func(s string, got, expected float64) {
+ if got != expected {
+ fmt.Printf("multiplyAdd: %s, expected %g, got %g\n", s, expected, got)
+ }
+ }
+ for _, t := range tests {
+ check(
+ fmt.Sprintf("float64(%v * %v) + %v", t.x, t.y, t.z),
+ func(x, y, z float64) float64 {
+ return float64(x*y) + z
+ }(t.x, t.y, t.z),
+ t.res)
+
+ check(
+ fmt.Sprintf("%v += float64(%v * %v)", t.z, t.x, t.y),
+ func(x, y, z float64) float64 {
+ z += float64(x * y)
+ return z
+ }(t.x, t.y, t.z),
+ t.res)
+ }
+ }
+ {
+ // Test that a multiply-accumulate operation with intermediate
+ // rounding forced by a complex128() cast produces the expected
+ // result.
+ // Test cases generated experimentally on a system (s390x) that
+ // supports fused multiply-add instructions.
+ var tests = [...]struct {
+ x, y float64
+ res complex128
+ }{
+ {0.6046602879796196, 0.9405090880450124, (2.754489951983871 + 3i)}, // fused multiply-add result: (2.7544899519838713 + 3i)
+ {0.09696951891448456, 0.30091186058528707, (0.5918204173287407 + 3i)}, // fused multiply-add result: (0.5918204173287408 + 3i)
+ {0.544155573000885, 0.27850762181610883, (1.910974340818764 + 3i)}, // fused multiply-add result: (1.9109743408187638 + 3i)
+ {0.9769168685862624, 0.07429099894984302, (3.0050416047086297 + 3i)}, // fused multiply-add result: (3.00504160470863 + 3i)
+ {0.9269868035744142, 0.9549454404167818, (3.735905851140024 + 3i)}, // fused multiply-add result: (3.7359058511400245 + 3i)
+ {0.7109071952999951, 0.5637795958152644, (2.69650118171525 + 3i)}, // fused multiply-add result: (2.6965011817152496 + 3i)
+ {0.7558235074915978, 0.40380328579570035, (2.671273808270494 + 3i)}, // fused multiply-add result: (2.6712738082704934 + 3i)
+ {0.13065111702897217, 0.9859647293402467, (1.3779180804271633 + 3i)}, // fused multiply-add result: (1.3779180804271631 + 3i)
+ {0.8963417453962161, 0.3220839705208817, (3.0111092067095298 + 3i)}, // fused multiply-add result: (3.01110920670953 + 3i)
+ {0.39998376285699544, 0.497868113342702, (1.697819401913688 + 3i)}, // fused multiply-add result: (1.6978194019136883 + 3i)
+ }
+ check := func(s string, got, expected complex128) {
+ if got != expected {
+ fmt.Printf("multiplyAdd: %s, expected %v, got %v\n", s, expected, got)
+ }
+ }
+ for _, t := range tests {
+ check(
+ fmt.Sprintf("complex128(complex(%v, 1)*3) + complex(%v, 0)", t.x, t.y),
+ func(x, y float64) complex128 {
+ return complex128(complex(x, 1)*3) + complex(y, 0)
+ }(t.x, t.y),
+ t.res)
+
+ check(
+ fmt.Sprintf("z := complex(%v, 1); z += complex128(complex(%v, 1) * 3)", t.y, t.x),
+ func(x, y float64) complex128 {
+ z := complex(y, 0)
+ z += complex128(complex(x, 1) * 3)
+ return z
+ }(t.x, t.y),
+ t.res)
+ }
+ }
+}
+
+const (
+ aa = 0x1000000000000000
+ ab = 0x100000000000000
+ ac = 0x10000000000000
+ ad = 0x1000000000000
+ ba = 0x100000000000
+ bb = 0x10000000000
+ bc = 0x1000000000
+ bd = 0x100000000
+ ca = 0x10000000
+ cb = 0x1000000
+ cc = 0x100000
+ cd = 0x10000
+ da = 0x1000
+ db = 0x100
+ dc = 0x10
+ dd = 0x1
+)
+
+//go:noinline
+func compares64_ssa(a, b, c, d float64) (lt, le, eq, ne, ge, gt uint64) {
+ if a < a {
+ lt += aa
+ }
+ if a < b {
+ lt += ab
+ }
+ if a < c {
+ lt += ac
+ }
+ if a < d {
+ lt += ad
+ }
+
+ if b < a {
+ lt += ba
+ }
+ if b < b {
+ lt += bb
+ }
+ if b < c {
+ lt += bc
+ }
+ if b < d {
+ lt += bd
+ }
+
+ if c < a {
+ lt += ca
+ }
+ if c < b {
+ lt += cb
+ }
+ if c < c {
+ lt += cc
+ }
+ if c < d {
+ lt += cd
+ }
+
+ if d < a {
+ lt += da
+ }
+ if d < b {
+ lt += db
+ }
+ if d < c {
+ lt += dc
+ }
+ if d < d {
+ lt += dd
+ }
+
+ if a <= a {
+ le += aa
+ }
+ if a <= b {
+ le += ab
+ }
+ if a <= c {
+ le += ac
+ }
+ if a <= d {
+ le += ad
+ }
+
+ if b <= a {
+ le += ba
+ }
+ if b <= b {
+ le += bb
+ }
+ if b <= c {
+ le += bc
+ }
+ if b <= d {
+ le += bd
+ }
+
+ if c <= a {
+ le += ca
+ }
+ if c <= b {
+ le += cb
+ }
+ if c <= c {
+ le += cc
+ }
+ if c <= d {
+ le += cd
+ }
+
+ if d <= a {
+ le += da
+ }
+ if d <= b {
+ le += db
+ }
+ if d <= c {
+ le += dc
+ }
+ if d <= d {
+ le += dd
+ }
+
+ if a == a {
+ eq += aa
+ }
+ if a == b {
+ eq += ab
+ }
+ if a == c {
+ eq += ac
+ }
+ if a == d {
+ eq += ad
+ }
+
+ if b == a {
+ eq += ba
+ }
+ if b == b {
+ eq += bb
+ }
+ if b == c {
+ eq += bc
+ }
+ if b == d {
+ eq += bd
+ }
+
+ if c == a {
+ eq += ca
+ }
+ if c == b {
+ eq += cb
+ }
+ if c == c {
+ eq += cc
+ }
+ if c == d {
+ eq += cd
+ }
+
+ if d == a {
+ eq += da
+ }
+ if d == b {
+ eq += db
+ }
+ if d == c {
+ eq += dc
+ }
+ if d == d {
+ eq += dd
+ }
+
+ if a != a {
+ ne += aa
+ }
+ if a != b {
+ ne += ab
+ }
+ if a != c {
+ ne += ac
+ }
+ if a != d {
+ ne += ad
+ }
+
+ if b != a {
+ ne += ba
+ }
+ if b != b {
+ ne += bb
+ }
+ if b != c {
+ ne += bc
+ }
+ if b != d {
+ ne += bd
+ }
+
+ if c != a {
+ ne += ca
+ }
+ if c != b {
+ ne += cb
+ }
+ if c != c {
+ ne += cc
+ }
+ if c != d {
+ ne += cd
+ }
+
+ if d != a {
+ ne += da
+ }
+ if d != b {
+ ne += db
+ }
+ if d != c {
+ ne += dc
+ }
+ if d != d {
+ ne += dd
+ }
+
+ if a >= a {
+ ge += aa
+ }
+ if a >= b {
+ ge += ab
+ }
+ if a >= c {
+ ge += ac
+ }
+ if a >= d {
+ ge += ad
+ }
+
+ if b >= a {
+ ge += ba
+ }
+ if b >= b {
+ ge += bb
+ }
+ if b >= c {
+ ge += bc
+ }
+ if b >= d {
+ ge += bd
+ }
+
+ if c >= a {
+ ge += ca
+ }
+ if c >= b {
+ ge += cb
+ }
+ if c >= c {
+ ge += cc
+ }
+ if c >= d {
+ ge += cd
+ }
+
+ if d >= a {
+ ge += da
+ }
+ if d >= b {
+ ge += db
+ }
+ if d >= c {
+ ge += dc
+ }
+ if d >= d {
+ ge += dd
+ }
+
+ if a > a {
+ gt += aa
+ }
+ if a > b {
+ gt += ab
+ }
+ if a > c {
+ gt += ac
+ }
+ if a > d {
+ gt += ad
+ }
+
+ if b > a {
+ gt += ba
+ }
+ if b > b {
+ gt += bb
+ }
+ if b > c {
+ gt += bc
+ }
+ if b > d {
+ gt += bd
+ }
+
+ if c > a {
+ gt += ca
+ }
+ if c > b {
+ gt += cb
+ }
+ if c > c {
+ gt += cc
+ }
+ if c > d {
+ gt += cd
+ }
+
+ if d > a {
+ gt += da
+ }
+ if d > b {
+ gt += db
+ }
+ if d > c {
+ gt += dc
+ }
+ if d > d {
+ gt += dd
+ }
+
+ return
+}
+
+//go:noinline
+func compares32_ssa(a, b, c, d float32) (lt, le, eq, ne, ge, gt uint64) {
+ if a < a {
+ lt += aa
+ }
+ if a < b {
+ lt += ab
+ }
+ if a < c {
+ lt += ac
+ }
+ if a < d {
+ lt += ad
+ }
+
+ if b < a {
+ lt += ba
+ }
+ if b < b {
+ lt += bb
+ }
+ if b < c {
+ lt += bc
+ }
+ if b < d {
+ lt += bd
+ }
+
+ if c < a {
+ lt += ca
+ }
+ if c < b {
+ lt += cb
+ }
+ if c < c {
+ lt += cc
+ }
+ if c < d {
+ lt += cd
+ }
+
+ if d < a {
+ lt += da
+ }
+ if d < b {
+ lt += db
+ }
+ if d < c {
+ lt += dc
+ }
+ if d < d {
+ lt += dd
+ }
+
+ if a <= a {
+ le += aa
+ }
+ if a <= b {
+ le += ab
+ }
+ if a <= c {
+ le += ac
+ }
+ if a <= d {
+ le += ad
+ }
+
+ if b <= a {
+ le += ba
+ }
+ if b <= b {
+ le += bb
+ }
+ if b <= c {
+ le += bc
+ }
+ if b <= d {
+ le += bd
+ }
+
+ if c <= a {
+ le += ca
+ }
+ if c <= b {
+ le += cb
+ }
+ if c <= c {
+ le += cc
+ }
+ if c <= d {
+ le += cd
+ }
+
+ if d <= a {
+ le += da
+ }
+ if d <= b {
+ le += db
+ }
+ if d <= c {
+ le += dc
+ }
+ if d <= d {
+ le += dd
+ }
+
+ if a == a {
+ eq += aa
+ }
+ if a == b {
+ eq += ab
+ }
+ if a == c {
+ eq += ac
+ }
+ if a == d {
+ eq += ad
+ }
+
+ if b == a {
+ eq += ba
+ }
+ if b == b {
+ eq += bb
+ }
+ if b == c {
+ eq += bc
+ }
+ if b == d {
+ eq += bd
+ }
+
+ if c == a {
+ eq += ca
+ }
+ if c == b {
+ eq += cb
+ }
+ if c == c {
+ eq += cc
+ }
+ if c == d {
+ eq += cd
+ }
+
+ if d == a {
+ eq += da
+ }
+ if d == b {
+ eq += db
+ }
+ if d == c {
+ eq += dc
+ }
+ if d == d {
+ eq += dd
+ }
+
+ if a != a {
+ ne += aa
+ }
+ if a != b {
+ ne += ab
+ }
+ if a != c {
+ ne += ac
+ }
+ if a != d {
+ ne += ad
+ }
+
+ if b != a {
+ ne += ba
+ }
+ if b != b {
+ ne += bb
+ }
+ if b != c {
+ ne += bc
+ }
+ if b != d {
+ ne += bd
+ }
+
+ if c != a {
+ ne += ca
+ }
+ if c != b {
+ ne += cb
+ }
+ if c != c {
+ ne += cc
+ }
+ if c != d {
+ ne += cd
+ }
+
+ if d != a {
+ ne += da
+ }
+ if d != b {
+ ne += db
+ }
+ if d != c {
+ ne += dc
+ }
+ if d != d {
+ ne += dd
+ }
+
+ if a >= a {
+ ge += aa
+ }
+ if a >= b {
+ ge += ab
+ }
+ if a >= c {
+ ge += ac
+ }
+ if a >= d {
+ ge += ad
+ }
+
+ if b >= a {
+ ge += ba
+ }
+ if b >= b {
+ ge += bb
+ }
+ if b >= c {
+ ge += bc
+ }
+ if b >= d {
+ ge += bd
+ }
+
+ if c >= a {
+ ge += ca
+ }
+ if c >= b {
+ ge += cb
+ }
+ if c >= c {
+ ge += cc
+ }
+ if c >= d {
+ ge += cd
+ }
+
+ if d >= a {
+ ge += da
+ }
+ if d >= b {
+ ge += db
+ }
+ if d >= c {
+ ge += dc
+ }
+ if d >= d {
+ ge += dd
+ }
+
+ if a > a {
+ gt += aa
+ }
+ if a > b {
+ gt += ab
+ }
+ if a > c {
+ gt += ac
+ }
+ if a > d {
+ gt += ad
+ }
+
+ if b > a {
+ gt += ba
+ }
+ if b > b {
+ gt += bb
+ }
+ if b > c {
+ gt += bc
+ }
+ if b > d {
+ gt += bd
+ }
+
+ if c > a {
+ gt += ca
+ }
+ if c > b {
+ gt += cb
+ }
+ if c > c {
+ gt += cc
+ }
+ if c > d {
+ gt += cd
+ }
+
+ if d > a {
+ gt += da
+ }
+ if d > b {
+ gt += db
+ }
+ if d > c {
+ gt += dc
+ }
+ if d > d {
+ gt += dd
+ }
+
+ return
+}
+
+//go:noinline
+func le64_ssa(x, y float64) bool {
+ return x <= y
+}
+
+//go:noinline
+func ge64_ssa(x, y float64) bool {
+ return x >= y
+}
+
+//go:noinline
+func lt64_ssa(x, y float64) bool {
+ return x < y
+}
+
+//go:noinline
+func gt64_ssa(x, y float64) bool {
+ return x > y
+}
+
+//go:noinline
+func eq64_ssa(x, y float64) bool {
+ return x == y
+}
+
+//go:noinline
+func ne64_ssa(x, y float64) bool {
+ return x != y
+}
+
+//go:noinline
+func eqbr64_ssa(x, y float64) float64 {
+ if x == y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func nebr64_ssa(x, y float64) float64 {
+ if x != y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func gebr64_ssa(x, y float64) float64 {
+ if x >= y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func lebr64_ssa(x, y float64) float64 {
+ if x <= y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func ltbr64_ssa(x, y float64) float64 {
+ if x < y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func gtbr64_ssa(x, y float64) float64 {
+ if x > y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func le32_ssa(x, y float32) bool {
+ return x <= y
+}
+
+//go:noinline
+func ge32_ssa(x, y float32) bool {
+ return x >= y
+}
+
+//go:noinline
+func lt32_ssa(x, y float32) bool {
+ return x < y
+}
+
+//go:noinline
+func gt32_ssa(x, y float32) bool {
+ return x > y
+}
+
+//go:noinline
+func eq32_ssa(x, y float32) bool {
+ return x == y
+}
+
+//go:noinline
+func ne32_ssa(x, y float32) bool {
+ return x != y
+}
+
+//go:noinline
+func eqbr32_ssa(x, y float32) float32 {
+ if x == y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func nebr32_ssa(x, y float32) float32 {
+ if x != y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func gebr32_ssa(x, y float32) float32 {
+ if x >= y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func lebr32_ssa(x, y float32) float32 {
+ if x <= y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func ltbr32_ssa(x, y float32) float32 {
+ if x < y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func gtbr32_ssa(x, y float32) float32 {
+ if x > y {
+ return 17
+ }
+ return 42
+}
+
+//go:noinline
+func F32toU8_ssa(x float32) uint8 {
+ return uint8(x)
+}
+
+//go:noinline
+func F32toI8_ssa(x float32) int8 {
+ return int8(x)
+}
+
+//go:noinline
+func F32toU16_ssa(x float32) uint16 {
+ return uint16(x)
+}
+
+//go:noinline
+func F32toI16_ssa(x float32) int16 {
+ return int16(x)
+}
+
+//go:noinline
+func F32toU32_ssa(x float32) uint32 {
+ return uint32(x)
+}
+
+//go:noinline
+func F32toI32_ssa(x float32) int32 {
+ return int32(x)
+}
+
+//go:noinline
+func F32toU64_ssa(x float32) uint64 {
+ return uint64(x)
+}
+
+//go:noinline
+func F32toI64_ssa(x float32) int64 {
+ return int64(x)
+}
+
+//go:noinline
+func F64toU8_ssa(x float64) uint8 {
+ return uint8(x)
+}
+
+//go:noinline
+func F64toI8_ssa(x float64) int8 {
+ return int8(x)
+}
+
+//go:noinline
+func F64toU16_ssa(x float64) uint16 {
+ return uint16(x)
+}
+
+//go:noinline
+func F64toI16_ssa(x float64) int16 {
+ return int16(x)
+}
+
+//go:noinline
+func F64toU32_ssa(x float64) uint32 {
+ return uint32(x)
+}
+
+//go:noinline
+func F64toI32_ssa(x float64) int32 {
+ return int32(x)
+}
+
+//go:noinline
+func F64toU64_ssa(x float64) uint64 {
+ return uint64(x)
+}
+
+//go:noinline
+func F64toI64_ssa(x float64) int64 {
+ return int64(x)
+}
+
+func floatsToInts(t *testing.T, x float64, expected int64) {
+ y := float32(x)
+ expectInt64(t, "F64toI8", int64(F64toI8_ssa(x)), expected)
+ expectInt64(t, "F64toI16", int64(F64toI16_ssa(x)), expected)
+ expectInt64(t, "F64toI32", int64(F64toI32_ssa(x)), expected)
+ expectInt64(t, "F64toI64", int64(F64toI64_ssa(x)), expected)
+ expectInt64(t, "F32toI8", int64(F32toI8_ssa(y)), expected)
+ expectInt64(t, "F32toI16", int64(F32toI16_ssa(y)), expected)
+ expectInt64(t, "F32toI32", int64(F32toI32_ssa(y)), expected)
+ expectInt64(t, "F32toI64", int64(F32toI64_ssa(y)), expected)
+}
+
+func floatsToUints(t *testing.T, x float64, expected uint64) {
+ y := float32(x)
+ expectUint64(t, "F64toU8", uint64(F64toU8_ssa(x)), expected)
+ expectUint64(t, "F64toU16", uint64(F64toU16_ssa(x)), expected)
+ expectUint64(t, "F64toU32", uint64(F64toU32_ssa(x)), expected)
+ expectUint64(t, "F64toU64", uint64(F64toU64_ssa(x)), expected)
+ expectUint64(t, "F32toU8", uint64(F32toU8_ssa(y)), expected)
+ expectUint64(t, "F32toU16", uint64(F32toU16_ssa(y)), expected)
+ expectUint64(t, "F32toU32", uint64(F32toU32_ssa(y)), expected)
+ expectUint64(t, "F32toU64", uint64(F32toU64_ssa(y)), expected)
+}
+
+func floatingToIntegerConversionsTest(t *testing.T) {
+ floatsToInts(t, 0.0, 0)
+ floatsToInts(t, 0.5, 0)
+ floatsToInts(t, 0.9, 0)
+ floatsToInts(t, 1.0, 1)
+ floatsToInts(t, 1.5, 1)
+ floatsToInts(t, 127.0, 127)
+ floatsToInts(t, -1.0, -1)
+ floatsToInts(t, -128.0, -128)
+
+ floatsToUints(t, 0.0, 0)
+ floatsToUints(t, 1.0, 1)
+ floatsToUints(t, 255.0, 255)
+
+ for j := uint(0); j < 24; j++ {
+ // Avoid hard cases in the construction
+ // of the test inputs.
+ v := int64(1<<62) | int64(1<<(62-j))
+ w := uint64(v)
+ f := float32(v)
+ d := float64(v)
+ expectUint64(t, "2**62...", F32toU64_ssa(f), w)
+ expectUint64(t, "2**62...", F64toU64_ssa(d), w)
+ expectInt64(t, "2**62...", F32toI64_ssa(f), v)
+ expectInt64(t, "2**62...", F64toI64_ssa(d), v)
+ expectInt64(t, "2**62...", F32toI64_ssa(-f), -v)
+ expectInt64(t, "2**62...", F64toI64_ssa(-d), -v)
+ w += w
+ f += f
+ d += d
+ expectUint64(t, "2**63...", F32toU64_ssa(f), w)
+ expectUint64(t, "2**63...", F64toU64_ssa(d), w)
+ }
+
+ for j := uint(0); j < 16; j++ {
+ // Avoid hard cases in the construction
+ // of the test inputs.
+ v := int32(1<<30) | int32(1<<(30-j))
+ w := uint32(v)
+ f := float32(v)
+ d := float64(v)
+ expectUint32(t, "2**30...", F32toU32_ssa(f), w)
+ expectUint32(t, "2**30...", F64toU32_ssa(d), w)
+ expectInt32(t, "2**30...", F32toI32_ssa(f), v)
+ expectInt32(t, "2**30...", F64toI32_ssa(d), v)
+ expectInt32(t, "2**30...", F32toI32_ssa(-f), -v)
+ expectInt32(t, "2**30...", F64toI32_ssa(-d), -v)
+ w += w
+ f += f
+ d += d
+ expectUint32(t, "2**31...", F32toU32_ssa(f), w)
+ expectUint32(t, "2**31...", F64toU32_ssa(d), w)
+ }
+
+ for j := uint(0); j < 15; j++ {
+ // Avoid hard cases in the construction
+ // of the test inputs.
+ v := int16(1<<14) | int16(1<<(14-j))
+ w := uint16(v)
+ f := float32(v)
+ d := float64(v)
+ expectUint16(t, "2**14...", F32toU16_ssa(f), w)
+ expectUint16(t, "2**14...", F64toU16_ssa(d), w)
+ expectInt16(t, "2**14...", F32toI16_ssa(f), v)
+ expectInt16(t, "2**14...", F64toI16_ssa(d), v)
+ expectInt16(t, "2**14...", F32toI16_ssa(-f), -v)
+ expectInt16(t, "2**14...", F64toI16_ssa(-d), -v)
+ w += w
+ f += f
+ d += d
+ expectUint16(t, "2**15...", F32toU16_ssa(f), w)
+ expectUint16(t, "2**15...", F64toU16_ssa(d), w)
+ }
+
+ expectInt32(t, "-2147483648", F32toI32_ssa(-2147483648), -2147483648)
+
+ expectInt32(t, "-2147483648", F64toI32_ssa(-2147483648), -2147483648)
+ expectInt32(t, "-2147483647", F64toI32_ssa(-2147483647), -2147483647)
+ expectUint32(t, "4294967295", F64toU32_ssa(4294967295), 4294967295)
+
+ expectInt16(t, "-32768", F64toI16_ssa(-32768), -32768)
+ expectInt16(t, "-32768", F32toI16_ssa(-32768), -32768)
+
+ // NB more of a pain to do these for 32-bit because of lost bits in Float32 mantissa
+ expectInt16(t, "32767", F64toI16_ssa(32767), 32767)
+ expectInt16(t, "32767", F32toI16_ssa(32767), 32767)
+ expectUint16(t, "32767", F64toU16_ssa(32767), 32767)
+ expectUint16(t, "32767", F32toU16_ssa(32767), 32767)
+ expectUint16(t, "65535", F64toU16_ssa(65535), 65535)
+ expectUint16(t, "65535", F32toU16_ssa(65535), 65535)
+}
+
+func fail64(s string, f func(a, b float64) float64, a, b, e float64) {
+ d := f(a, b)
+ if d != e {
+ fmt.Printf("For (float64) %v %v %v, expected %v, got %v\n", a, s, b, e, d)
+ }
+}
+
+func fail64bool(s string, f func(a, b float64) bool, a, b float64, e bool) {
+ d := f(a, b)
+ if d != e {
+ fmt.Printf("For (float64) %v %v %v, expected %v, got %v\n", a, s, b, e, d)
+ }
+}
+
+func fail32(s string, f func(a, b float32) float32, a, b, e float32) {
+ d := f(a, b)
+ if d != e {
+ fmt.Printf("For (float32) %v %v %v, expected %v, got %v\n", a, s, b, e, d)
+ }
+}
+
+func fail32bool(s string, f func(a, b float32) bool, a, b float32, e bool) {
+ d := f(a, b)
+ if d != e {
+ fmt.Printf("For (float32) %v %v %v, expected %v, got %v\n", a, s, b, e, d)
+ }
+}
+
+func expect64(t *testing.T, s string, x, expected float64) {
+ if x != expected {
+ println("F64 Expected", expected, "for", s, ", got", x)
+ }
+}
+
+func expect32(t *testing.T, s string, x, expected float32) {
+ if x != expected {
+ println("F32 Expected", expected, "for", s, ", got", x)
+ }
+}
+
+func expectUint64(t *testing.T, s string, x, expected uint64) {
+ if x != expected {
+ fmt.Printf("U64 Expected 0x%016x for %s, got 0x%016x\n", expected, s, x)
+ }
+}
+
+func expectInt64(t *testing.T, s string, x, expected int64) {
+ if x != expected {
+ fmt.Printf("%s: Expected 0x%016x, got 0x%016x\n", s, expected, x)
+ }
+}
+
+func expectUint32(t *testing.T, s string, x, expected uint32) {
+ if x != expected {
+ fmt.Printf("U32 %s: Expected 0x%08x, got 0x%08x\n", s, expected, x)
+ }
+}
+
+func expectInt32(t *testing.T, s string, x, expected int32) {
+ if x != expected {
+ fmt.Printf("I32 %s: Expected 0x%08x, got 0x%08x\n", s, expected, x)
+ }
+}
+
+func expectUint16(t *testing.T, s string, x, expected uint16) {
+ if x != expected {
+ fmt.Printf("U16 %s: Expected 0x%04x, got 0x%04x\n", s, expected, x)
+ }
+}
+
+func expectInt16(t *testing.T, s string, x, expected int16) {
+ if x != expected {
+ fmt.Printf("I16 %s: Expected 0x%04x, got 0x%04x\n", s, expected, x)
+ }
+}
+
+func expectAll64(t *testing.T, s string, expected, a, b, c, d, e, f, g, h, i float64) {
+ expect64(t, s+":a", a, expected)
+ expect64(t, s+":b", b, expected)
+ expect64(t, s+":c", c, expected)
+ expect64(t, s+":d", d, expected)
+ expect64(t, s+":e", e, expected)
+ expect64(t, s+":f", f, expected)
+ expect64(t, s+":g", g, expected)
+}
+
+func expectAll32(t *testing.T, s string, expected, a, b, c, d, e, f, g, h, i float32) {
+ expect32(t, s+":a", a, expected)
+ expect32(t, s+":b", b, expected)
+ expect32(t, s+":c", c, expected)
+ expect32(t, s+":d", d, expected)
+ expect32(t, s+":e", e, expected)
+ expect32(t, s+":f", f, expected)
+ expect32(t, s+":g", g, expected)
+}
+
+var ev64 [2]float64 = [2]float64{42.0, 17.0}
+var ev32 [2]float32 = [2]float32{42.0, 17.0}
+
+func cmpOpTest(t *testing.T,
+ s string,
+ f func(a, b float64) bool,
+ g func(a, b float64) float64,
+ ff func(a, b float32) bool,
+ gg func(a, b float32) float32,
+ zero, one, inf, nan float64, result uint) {
+ fail64bool(s, f, zero, zero, result>>16&1 == 1)
+ fail64bool(s, f, zero, one, result>>12&1 == 1)
+ fail64bool(s, f, zero, inf, result>>8&1 == 1)
+ fail64bool(s, f, zero, nan, result>>4&1 == 1)
+ fail64bool(s, f, nan, nan, result&1 == 1)
+
+ fail64(s, g, zero, zero, ev64[result>>16&1])
+ fail64(s, g, zero, one, ev64[result>>12&1])
+ fail64(s, g, zero, inf, ev64[result>>8&1])
+ fail64(s, g, zero, nan, ev64[result>>4&1])
+ fail64(s, g, nan, nan, ev64[result>>0&1])
+
+ {
+ zero := float32(zero)
+ one := float32(one)
+ inf := float32(inf)
+ nan := float32(nan)
+ fail32bool(s, ff, zero, zero, (result>>16)&1 == 1)
+ fail32bool(s, ff, zero, one, (result>>12)&1 == 1)
+ fail32bool(s, ff, zero, inf, (result>>8)&1 == 1)
+ fail32bool(s, ff, zero, nan, (result>>4)&1 == 1)
+ fail32bool(s, ff, nan, nan, result&1 == 1)
+
+ fail32(s, gg, zero, zero, ev32[(result>>16)&1])
+ fail32(s, gg, zero, one, ev32[(result>>12)&1])
+ fail32(s, gg, zero, inf, ev32[(result>>8)&1])
+ fail32(s, gg, zero, nan, ev32[(result>>4)&1])
+ fail32(s, gg, nan, nan, ev32[(result>>0)&1])
+ }
+}
+
+func expectCx128(t *testing.T, s string, x, expected complex128) {
+ if x != expected {
+ t.Errorf("Cx 128 Expected %f for %s, got %f", expected, s, x)
+ }
+}
+
+func expectCx64(t *testing.T, s string, x, expected complex64) {
+ if x != expected {
+ t.Errorf("Cx 64 Expected %f for %s, got %f", expected, s, x)
+ }
+}
+
+//go:noinline
+func cx128sum_ssa(a, b complex128) complex128 {
+ return a + b
+}
+
+//go:noinline
+func cx128diff_ssa(a, b complex128) complex128 {
+ return a - b
+}
+
+//go:noinline
+func cx128prod_ssa(a, b complex128) complex128 {
+ return a * b
+}
+
+//go:noinline
+func cx128quot_ssa(a, b complex128) complex128 {
+ return a / b
+}
+
+//go:noinline
+func cx128neg_ssa(a complex128) complex128 {
+ return -a
+}
+
+//go:noinline
+func cx128real_ssa(a complex128) float64 {
+ return real(a)
+}
+
+//go:noinline
+func cx128imag_ssa(a complex128) float64 {
+ return imag(a)
+}
+
+//go:noinline
+func cx128cnst_ssa(a complex128) complex128 {
+ b := 2 + 3i
+ return a * b
+}
+
+//go:noinline
+func cx64sum_ssa(a, b complex64) complex64 {
+ return a + b
+}
+
+//go:noinline
+func cx64diff_ssa(a, b complex64) complex64 {
+ return a - b
+}
+
+//go:noinline
+func cx64prod_ssa(a, b complex64) complex64 {
+ return a * b
+}
+
+//go:noinline
+func cx64quot_ssa(a, b complex64) complex64 {
+ return a / b
+}
+
+//go:noinline
+func cx64neg_ssa(a complex64) complex64 {
+ return -a
+}
+
+//go:noinline
+func cx64real_ssa(a complex64) float32 {
+ return real(a)
+}
+
+//go:noinline
+func cx64imag_ssa(a complex64) float32 {
+ return imag(a)
+}
+
+//go:noinline
+func cx128eq_ssa(a, b complex128) bool {
+ return a == b
+}
+
+//go:noinline
+func cx128ne_ssa(a, b complex128) bool {
+ return a != b
+}
+
+//go:noinline
+func cx64eq_ssa(a, b complex64) bool {
+ return a == b
+}
+
+//go:noinline
+func cx64ne_ssa(a, b complex64) bool {
+ return a != b
+}
+
+func expectTrue(t *testing.T, s string, b bool) {
+ if !b {
+ t.Errorf("expected true for %s, got false", s)
+ }
+}
+func expectFalse(t *testing.T, s string, b bool) {
+ if b {
+ t.Errorf("expected false for %s, got true", s)
+ }
+}
+
+func complexTest128(t *testing.T) {
+ var a complex128 = 1 + 2i
+ var b complex128 = 3 + 6i
+ sum := cx128sum_ssa(b, a)
+ diff := cx128diff_ssa(b, a)
+ prod := cx128prod_ssa(b, a)
+ quot := cx128quot_ssa(b, a)
+ neg := cx128neg_ssa(a)
+ r := cx128real_ssa(a)
+ i := cx128imag_ssa(a)
+ cnst := cx128cnst_ssa(a)
+ c1 := cx128eq_ssa(a, a)
+ c2 := cx128eq_ssa(a, b)
+ c3 := cx128ne_ssa(a, a)
+ c4 := cx128ne_ssa(a, b)
+
+ expectCx128(t, "sum", sum, 4+8i)
+ expectCx128(t, "diff", diff, 2+4i)
+ expectCx128(t, "prod", prod, -9+12i)
+ expectCx128(t, "quot", quot, 3+0i)
+ expectCx128(t, "neg", neg, -1-2i)
+ expect64(t, "real", r, 1)
+ expect64(t, "imag", i, 2)
+ expectCx128(t, "cnst", cnst, -4+7i)
+ expectTrue(t, fmt.Sprintf("%v==%v", a, a), c1)
+ expectFalse(t, fmt.Sprintf("%v==%v", a, b), c2)
+ expectFalse(t, fmt.Sprintf("%v!=%v", a, a), c3)
+ expectTrue(t, fmt.Sprintf("%v!=%v", a, b), c4)
+}
+
+func complexTest64(t *testing.T) {
+ var a complex64 = 1 + 2i
+ var b complex64 = 3 + 6i
+ sum := cx64sum_ssa(b, a)
+ diff := cx64diff_ssa(b, a)
+ prod := cx64prod_ssa(b, a)
+ quot := cx64quot_ssa(b, a)
+ neg := cx64neg_ssa(a)
+ r := cx64real_ssa(a)
+ i := cx64imag_ssa(a)
+ c1 := cx64eq_ssa(a, a)
+ c2 := cx64eq_ssa(a, b)
+ c3 := cx64ne_ssa(a, a)
+ c4 := cx64ne_ssa(a, b)
+
+ expectCx64(t, "sum", sum, 4+8i)
+ expectCx64(t, "diff", diff, 2+4i)
+ expectCx64(t, "prod", prod, -9+12i)
+ expectCx64(t, "quot", quot, 3+0i)
+ expectCx64(t, "neg", neg, -1-2i)
+ expect32(t, "real", r, 1)
+ expect32(t, "imag", i, 2)
+ expectTrue(t, fmt.Sprintf("%v==%v", a, a), c1)
+ expectFalse(t, fmt.Sprintf("%v==%v", a, b), c2)
+ expectFalse(t, fmt.Sprintf("%v!=%v", a, a), c3)
+ expectTrue(t, fmt.Sprintf("%v!=%v", a, b), c4)
+}
+
+// TestFP tests that we get the right answer for floating point expressions.
+func TestFP(t *testing.T) {
+ a := 3.0
+ b := 4.0
+
+ c := float32(3.0)
+ d := float32(4.0)
+
+ tiny := float32(1.5e-45) // smallest f32 denorm = 2**(-149)
+ dtiny := float64(tiny) // well within range of f64
+
+ fail64("+", add64_ssa, a, b, 7.0)
+ fail64("*", mul64_ssa, a, b, 12.0)
+ fail64("-", sub64_ssa, a, b, -1.0)
+ fail64("/", div64_ssa, a, b, 0.75)
+ fail64("neg", neg64_ssa, a, b, -7)
+
+ fail32("+", add32_ssa, c, d, 7.0)
+ fail32("*", mul32_ssa, c, d, 12.0)
+ fail32("-", sub32_ssa, c, d, -1.0)
+ fail32("/", div32_ssa, c, d, 0.75)
+ fail32("neg", neg32_ssa, c, d, -7)
+
+ // denorm-squared should underflow to zero.
+ fail32("*", mul32_ssa, tiny, tiny, 0)
+
+ // but should not underflow in float and in fact is exactly representable.
+ fail64("*", mul64_ssa, dtiny, dtiny, 1.9636373861190906e-90)
+
+ // Intended to create register pressure which forces
+ // asymmetric op into different code paths.
+ aa, ab, ac, ad, ba, bb, bc, bd, ca, cb, cc, cd, da, db, dc, dd := manysub_ssa(1000.0, 100.0, 10.0, 1.0)
+
+ expect64(t, "aa", aa, 11.0)
+ expect64(t, "ab", ab, 900.0)
+ expect64(t, "ac", ac, 990.0)
+ expect64(t, "ad", ad, 999.0)
+
+ expect64(t, "ba", ba, -900.0)
+ expect64(t, "bb", bb, 22.0)
+ expect64(t, "bc", bc, 90.0)
+ expect64(t, "bd", bd, 99.0)
+
+ expect64(t, "ca", ca, -990.0)
+ expect64(t, "cb", cb, -90.0)
+ expect64(t, "cc", cc, 33.0)
+ expect64(t, "cd", cd, 9.0)
+
+ expect64(t, "da", da, -999.0)
+ expect64(t, "db", db, -99.0)
+ expect64(t, "dc", dc, -9.0)
+ expect64(t, "dd", dd, 44.0)
+
+ integer2floatConversions(t)
+
+ multiplyAdd(t)
+
+ var zero64 float64 = 0.0
+ var one64 float64 = 1.0
+ var inf64 float64 = 1.0 / zero64
+ var nan64 float64 = sub64_ssa(inf64, inf64)
+
+ cmpOpTest(t, "!=", ne64_ssa, nebr64_ssa, ne32_ssa, nebr32_ssa, zero64, one64, inf64, nan64, 0x01111)
+ cmpOpTest(t, "==", eq64_ssa, eqbr64_ssa, eq32_ssa, eqbr32_ssa, zero64, one64, inf64, nan64, 0x10000)
+ cmpOpTest(t, "<=", le64_ssa, lebr64_ssa, le32_ssa, lebr32_ssa, zero64, one64, inf64, nan64, 0x11100)
+ cmpOpTest(t, "<", lt64_ssa, ltbr64_ssa, lt32_ssa, ltbr32_ssa, zero64, one64, inf64, nan64, 0x01100)
+ cmpOpTest(t, ">", gt64_ssa, gtbr64_ssa, gt32_ssa, gtbr32_ssa, zero64, one64, inf64, nan64, 0x00000)
+ cmpOpTest(t, ">=", ge64_ssa, gebr64_ssa, ge32_ssa, gebr32_ssa, zero64, one64, inf64, nan64, 0x10000)
+
+ {
+ lt, le, eq, ne, ge, gt := compares64_ssa(0.0, 1.0, inf64, nan64)
+ expectUint64(t, "lt", lt, 0x0110001000000000)
+ expectUint64(t, "le", le, 0x1110011000100000)
+ expectUint64(t, "eq", eq, 0x1000010000100000)
+ expectUint64(t, "ne", ne, 0x0111101111011111)
+ expectUint64(t, "ge", ge, 0x1000110011100000)
+ expectUint64(t, "gt", gt, 0x0000100011000000)
+ // fmt.Printf("lt=0x%016x, le=0x%016x, eq=0x%016x, ne=0x%016x, ge=0x%016x, gt=0x%016x\n",
+ // lt, le, eq, ne, ge, gt)
+ }
+ {
+ lt, le, eq, ne, ge, gt := compares32_ssa(0.0, 1.0, float32(inf64), float32(nan64))
+ expectUint64(t, "lt", lt, 0x0110001000000000)
+ expectUint64(t, "le", le, 0x1110011000100000)
+ expectUint64(t, "eq", eq, 0x1000010000100000)
+ expectUint64(t, "ne", ne, 0x0111101111011111)
+ expectUint64(t, "ge", ge, 0x1000110011100000)
+ expectUint64(t, "gt", gt, 0x0000100011000000)
+ }
+
+ floatingToIntegerConversionsTest(t)
+ complexTest128(t)
+ complexTest64(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
new file mode 100644
index 0000000..21ad27e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
@@ -0,0 +1,209 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This program generates a test to verify that the standard arithmetic
+// operators properly handle some special cases. The test file should be
+// generated with a known working version of go.
+// launch with `go run arithBoundaryGen.go` a file called arithBoundary.go
+// will be written into the parent directory containing the tests
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "text/template"
+)
+
+// used for interpolation in a text template
+type tmplData struct {
+ Name, Stype, Symbol string
+}
+
+// used to work around an issue with the mod symbol being
+// interpreted as part of a format string
+func (s tmplData) SymFirst() string {
+ return string(s.Symbol[0])
+}
+
+// ucast casts an unsigned int to the size in s
+func ucast(i uint64, s sizedTestData) uint64 {
+ switch s.name {
+ case "uint32":
+ return uint64(uint32(i))
+ case "uint16":
+ return uint64(uint16(i))
+ case "uint8":
+ return uint64(uint8(i))
+ }
+ return i
+}
+
+// icast casts a signed int to the size in s
+func icast(i int64, s sizedTestData) int64 {
+ switch s.name {
+ case "int32":
+ return int64(int32(i))
+ case "int16":
+ return int64(int16(i))
+ case "int8":
+ return int64(int8(i))
+ }
+ return i
+}
+
+type sizedTestData struct {
+ name string
+ sn string
+ u []uint64
+ i []int64
+}
+
+// values to generate tests. these should include the smallest and largest values, along
+// with any other values that might cause issues. we generate n^2 tests for each size to
+// cover all cases.
+var szs = []sizedTestData{
+ sizedTestData{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
+ sizedTestData{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+ -4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
+
+ sizedTestData{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
+ sizedTestData{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0,
+ 1, 0x7FFFFFFF}},
+
+ sizedTestData{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
+ sizedTestData{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}},
+
+ sizedTestData{name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
+ sizedTestData{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}},
+}
+
+type op struct {
+ name, symbol string
+}
+
+// ops that we will be generating tests for
+var ops = []op{op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mod", "%%"}, op{"mul", "*"}}
+
+func main() {
+ w := new(bytes.Buffer)
+ fmt.Fprintf(w, "// Code generated by gen/arithBoundaryGen.go. DO NOT EDIT.\n\n")
+ fmt.Fprintf(w, "package main;\n")
+ fmt.Fprintf(w, "import \"testing\"\n")
+
+ for _, sz := range []int{64, 32, 16, 8} {
+ fmt.Fprintf(w, "type utd%d struct {\n", sz)
+ fmt.Fprintf(w, " a,b uint%d\n", sz)
+ fmt.Fprintf(w, " add,sub,mul,div,mod uint%d\n", sz)
+ fmt.Fprintf(w, "}\n")
+
+ fmt.Fprintf(w, "type itd%d struct {\n", sz)
+ fmt.Fprintf(w, " a,b int%d\n", sz)
+ fmt.Fprintf(w, " add,sub,mul,div,mod int%d\n", sz)
+ fmt.Fprintf(w, "}\n")
+ }
+
+ // the function being tested
+ testFunc, err := template.New("testFunc").Parse(
+ `//go:noinline
+ func {{.Name}}_{{.Stype}}_ssa(a, b {{.Stype}}) {{.Stype}} {
+ return a {{.SymFirst}} b
+}
+`)
+ if err != nil {
+ panic(err)
+ }
+
+ // generate our functions to be tested
+ for _, s := range szs {
+ for _, o := range ops {
+ fd := tmplData{o.name, s.name, o.symbol}
+ err = testFunc.Execute(w, fd)
+ if err != nil {
+ panic(err)
+ }
+ }
+ }
+
+ // generate the test data
+ for _, s := range szs {
+ if len(s.u) > 0 {
+ fmt.Fprintf(w, "var %s_data []utd%s = []utd%s{", s.name, s.sn, s.sn)
+ for _, i := range s.u {
+ for _, j := range s.u {
+ fmt.Fprintf(w, "utd%s{a: %d, b: %d, add: %d, sub: %d, mul: %d", s.sn, i, j, ucast(i+j, s), ucast(i-j, s), ucast(i*j, s))
+ if j != 0 {
+ fmt.Fprintf(w, ", div: %d, mod: %d", ucast(i/j, s), ucast(i%j, s))
+ }
+ fmt.Fprint(w, "},\n")
+ }
+ }
+ fmt.Fprintf(w, "}\n")
+ } else {
+ // TODO: clean up this duplication
+ fmt.Fprintf(w, "var %s_data []itd%s = []itd%s{", s.name, s.sn, s.sn)
+ for _, i := range s.i {
+ for _, j := range s.i {
+ fmt.Fprintf(w, "itd%s{a: %d, b: %d, add: %d, sub: %d, mul: %d", s.sn, i, j, icast(i+j, s), icast(i-j, s), icast(i*j, s))
+ if j != 0 {
+ fmt.Fprintf(w, ", div: %d, mod: %d", icast(i/j, s), icast(i%j, s))
+ }
+ fmt.Fprint(w, "},\n")
+ }
+ }
+ fmt.Fprintf(w, "}\n")
+ }
+ }
+
+ fmt.Fprintf(w, "//TestArithmeticBoundary tests boundary results for arithmetic operations.\n")
+ fmt.Fprintf(w, "func TestArithmeticBoundary(t *testing.T) {\n\n")
+
+ verify, err := template.New("tst").Parse(
+ `if got := {{.Name}}_{{.Stype}}_ssa(v.a, v.b); got != v.{{.Name}} {
+ t.Errorf("{{.Name}}_{{.Stype}} %d{{.Symbol}}%d = %d, wanted %d\n",v.a,v.b,got,v.{{.Name}})
+}
+`)
+
+ for _, s := range szs {
+ fmt.Fprintf(w, "for _, v := range %s_data {\n", s.name)
+
+ for _, o := range ops {
+ // avoid generating tests that divide by zero
+ if o.name == "div" || o.name == "mod" {
+ fmt.Fprint(w, "if v.b != 0 {")
+ }
+
+ err = verify.Execute(w, tmplData{o.name, s.name, o.symbol})
+
+ if o.name == "div" || o.name == "mod" {
+ fmt.Fprint(w, "\n}\n")
+ }
+
+ if err != nil {
+ panic(err)
+ }
+
+ }
+ fmt.Fprint(w, " }\n")
+ }
+
+ fmt.Fprintf(w, "}\n")
+
+ // gofmt result
+ b := w.Bytes()
+ src, err := format.Source(b)
+ if err != nil {
+ fmt.Printf("%s\n", b)
+ panic(err)
+ }
+
+ // write to file
+ err = ioutil.WriteFile("../arithBoundary_test.go", src, 0666)
+ if err != nil {
+ log.Fatalf("can't write output: %v\n", err)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
new file mode 100644
index 0000000..41b2946
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
@@ -0,0 +1,346 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This program generates a test to verify that the standard arithmetic
+// operators properly handle const cases. The test file should be
+// generated with a known working version of go.
+// launch with `go run arithConstGen.go` a file called arithConst.go
+// will be written into the parent directory containing the tests
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "strings"
+ "text/template"
+)
+
+type op struct {
+ name, symbol string
+}
+type szD struct {
+ name string
+ sn string
+ u []uint64
+ i []int64
+ oponly string
+}
+
+var szs = []szD{
+ {name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0x8000000000000000, 0xffffFFFFffffFFFF}},
+ {name: "uint64", sn: "64", u: []uint64{3, 5, 7, 9, 10, 11, 13, 19, 21, 25, 27, 37, 41, 45, 73, 81}, oponly: "mul"},
+
+ {name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+ -4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
+ {name: "int64", sn: "64", i: []int64{-9, -5, -3, 3, 5, 7, 9, 10, 11, 13, 19, 21, 25, 27, 37, 41, 45, 73, 81}, oponly: "mul"},
+
+ {name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
+ {name: "uint32", sn: "32", u: []uint64{3, 5, 7, 9, 10, 11, 13, 19, 21, 25, 27, 37, 41, 45, 73, 81}, oponly: "mul"},
+
+ {name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0,
+ 1, 0x7FFFFFFF}},
+ {name: "int32", sn: "32", i: []int64{-9, -5, -3, 3, 5, 7, 9, 10, 11, 13, 19, 21, 25, 27, 37, 41, 45, 73, 81}, oponly: "mul"},
+
+ {name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
+ {name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}},
+
+ {name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
+ {name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}},
+}
+
+var ops = []op{
+ {"add", "+"},
+ {"sub", "-"},
+ {"div", "/"},
+ {"mul", "*"},
+ {"lsh", "<<"},
+ {"rsh", ">>"},
+ {"mod", "%"},
+ {"and", "&"},
+ {"or", "|"},
+ {"xor", "^"},
+}
+
+// compute the result of i op j, cast as type t.
+func ansU(i, j uint64, t, op string) string {
+ var ans uint64
+ switch op {
+ case "+":
+ ans = i + j
+ case "-":
+ ans = i - j
+ case "*":
+ ans = i * j
+ case "/":
+ if j != 0 {
+ ans = i / j
+ }
+ case "%":
+ if j != 0 {
+ ans = i % j
+ }
+ case "<<":
+ ans = i << j
+ case ">>":
+ ans = i >> j
+ case "&":
+ ans = i & j
+ case "|":
+ ans = i | j
+ case "^":
+ ans = i ^ j
+ }
+ switch t {
+ case "uint32":
+ ans = uint64(uint32(ans))
+ case "uint16":
+ ans = uint64(uint16(ans))
+ case "uint8":
+ ans = uint64(uint8(ans))
+ }
+ return fmt.Sprintf("%d", ans)
+}
+
+// compute the result of i op j, cast as type t.
+func ansS(i, j int64, t, op string) string {
+ var ans int64
+ switch op {
+ case "+":
+ ans = i + j
+ case "-":
+ ans = i - j
+ case "*":
+ ans = i * j
+ case "/":
+ if j != 0 {
+ ans = i / j
+ }
+ case "%":
+ if j != 0 {
+ ans = i % j
+ }
+ case "<<":
+ ans = i << uint64(j)
+ case ">>":
+ ans = i >> uint64(j)
+ case "&":
+ ans = i & j
+ case "|":
+ ans = i | j
+ case "^":
+ ans = i ^ j
+ }
+ switch t {
+ case "int32":
+ ans = int64(int32(ans))
+ case "int16":
+ ans = int64(int16(ans))
+ case "int8":
+ ans = int64(int8(ans))
+ }
+ return fmt.Sprintf("%d", ans)
+}
+
+func main() {
+ w := new(bytes.Buffer)
+ fmt.Fprintf(w, "// Code generated by gen/arithConstGen.go. DO NOT EDIT.\n\n")
+ fmt.Fprintf(w, "package main;\n")
+ fmt.Fprintf(w, "import \"testing\"\n")
+
+ fncCnst1 := template.Must(template.New("fnc").Parse(
+ `//go:noinline
+func {{.Name}}_{{.Type_}}_{{.FNumber}}(a {{.Type_}}) {{.Type_}} { return a {{.Symbol}} {{.Number}} }
+`))
+ fncCnst2 := template.Must(template.New("fnc").Parse(
+ `//go:noinline
+func {{.Name}}_{{.FNumber}}_{{.Type_}}(a {{.Type_}}) {{.Type_}} { return {{.Number}} {{.Symbol}} a }
+`))
+
+ type fncData struct {
+ Name, Type_, Symbol, FNumber, Number string
+ }
+
+ for _, s := range szs {
+ for _, o := range ops {
+ if s.oponly != "" && s.oponly != o.name {
+ continue
+ }
+ fd := fncData{o.name, s.name, o.symbol, "", ""}
+
+ // unsigned test cases
+ if len(s.u) > 0 {
+ for _, i := range s.u {
+ fd.Number = fmt.Sprintf("%d", i)
+ fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1)
+
+ // avoid division by zero
+ if o.name != "mod" && o.name != "div" || i != 0 {
+ // introduce uint64 cast for rhs shift operands
+ // if they are too large for default uint type
+ number := fd.Number
+ if (o.name == "lsh" || o.name == "rsh") && uint64(uint32(i)) != i {
+ fd.Number = fmt.Sprintf("uint64(%s)", number)
+ }
+ fncCnst1.Execute(w, fd)
+ fd.Number = number
+ }
+
+ fncCnst2.Execute(w, fd)
+ }
+ }
+
+ // signed test cases
+ if len(s.i) > 0 {
+ // don't generate tests for shifts by signed integers
+ if o.name == "lsh" || o.name == "rsh" {
+ continue
+ }
+ for _, i := range s.i {
+ fd.Number = fmt.Sprintf("%d", i)
+ fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1)
+
+ // avoid division by zero
+ if o.name != "mod" && o.name != "div" || i != 0 {
+ fncCnst1.Execute(w, fd)
+ }
+ fncCnst2.Execute(w, fd)
+ }
+ }
+ }
+ }
+
+ vrf1 := template.Must(template.New("vrf1").Parse(`
+ test_{{.Size}}{fn: {{.Name}}_{{.FNumber}}_{{.Type_}}, fnname: "{{.Name}}_{{.FNumber}}_{{.Type_}}", in: {{.Input}}, want: {{.Ans}}},`))
+
+ vrf2 := template.Must(template.New("vrf2").Parse(`
+ test_{{.Size}}{fn: {{.Name}}_{{.Type_}}_{{.FNumber}}, fnname: "{{.Name}}_{{.Type_}}_{{.FNumber}}", in: {{.Input}}, want: {{.Ans}}},`))
+
+ type cfncData struct {
+ Size, Name, Type_, Symbol, FNumber, Number string
+ Ans, Input string
+ }
+ for _, s := range szs {
+ fmt.Fprintf(w, `
+type test_%[1]s%[2]s struct {
+ fn func (%[1]s) %[1]s
+ fnname string
+ in %[1]s
+ want %[1]s
+}
+`, s.name, s.oponly)
+ fmt.Fprintf(w, "var tests_%[1]s%[2]s =[]test_%[1]s {\n\n", s.name, s.oponly)
+
+ if len(s.u) > 0 {
+ for _, o := range ops {
+ if s.oponly != "" && s.oponly != o.name {
+ continue
+ }
+ fd := cfncData{s.name, o.name, s.name, o.symbol, "", "", "", ""}
+ for _, i := range s.u {
+ fd.Number = fmt.Sprintf("%d", i)
+ fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1)
+
+ // unsigned
+ for _, j := range s.u {
+
+ if o.name != "mod" && o.name != "div" || j != 0 {
+ fd.Ans = ansU(i, j, s.name, o.symbol)
+ fd.Input = fmt.Sprintf("%d", j)
+ if err := vrf1.Execute(w, fd); err != nil {
+ panic(err)
+ }
+ }
+
+ if o.name != "mod" && o.name != "div" || i != 0 {
+ fd.Ans = ansU(j, i, s.name, o.symbol)
+ fd.Input = fmt.Sprintf("%d", j)
+ if err := vrf2.Execute(w, fd); err != nil {
+ panic(err)
+ }
+ }
+
+ }
+ }
+
+ }
+ }
+
+ // signed
+ if len(s.i) > 0 {
+ for _, o := range ops {
+ if s.oponly != "" && s.oponly != o.name {
+ continue
+ }
+ // don't generate tests for shifts by signed integers
+ if o.name == "lsh" || o.name == "rsh" {
+ continue
+ }
+ fd := cfncData{s.name, o.name, s.name, o.symbol, "", "", "", ""}
+ for _, i := range s.i {
+ fd.Number = fmt.Sprintf("%d", i)
+ fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1)
+ for _, j := range s.i {
+ if o.name != "mod" && o.name != "div" || j != 0 {
+ fd.Ans = ansS(i, j, s.name, o.symbol)
+ fd.Input = fmt.Sprintf("%d", j)
+ if err := vrf1.Execute(w, fd); err != nil {
+ panic(err)
+ }
+ }
+
+ if o.name != "mod" && o.name != "div" || i != 0 {
+ fd.Ans = ansS(j, i, s.name, o.symbol)
+ fd.Input = fmt.Sprintf("%d", j)
+ if err := vrf2.Execute(w, fd); err != nil {
+ panic(err)
+ }
+ }
+
+ }
+ }
+
+ }
+ }
+
+ fmt.Fprintf(w, "}\n\n")
+ }
+
+ fmt.Fprint(w, `
+
+// TestArithmeticConst tests results for arithmetic operations against constants.
+func TestArithmeticConst(t *testing.T) {
+`)
+
+ for _, s := range szs {
+ fmt.Fprintf(w, `for _, test := range tests_%s%s {`, s.name, s.oponly)
+ // Use WriteString here to avoid a vet warning about formatting directives.
+ w.WriteString(`if got := test.fn(test.in); got != test.want {
+ t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want)
+ }
+ }
+`)
+ }
+
+ fmt.Fprint(w, `
+}
+`)
+
+ // gofmt result
+ b := w.Bytes()
+ src, err := format.Source(b)
+ if err != nil {
+ fmt.Printf("%s\n", b)
+ panic(err)
+ }
+
+ // write to file
+ err = ioutil.WriteFile("../arithConst_test.go", src, 0666)
+ if err != nil {
+ log.Fatalf("can't write output: %v\n", err)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go b/src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go
new file mode 100644
index 0000000..5508e76
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go
@@ -0,0 +1,247 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This program generates a test to verify that the standard comparison
+// operators properly handle one const operand. The test file should be
+// generated with a known working version of go.
+// launch with `go run cmpConstGen.go` a file called cmpConst.go
+// will be written into the parent directory containing the tests
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "math/big"
+ "sort"
+)
+
+const (
+ maxU64 = (1 << 64) - 1
+ maxU32 = (1 << 32) - 1
+ maxU16 = (1 << 16) - 1
+ maxU8 = (1 << 8) - 1
+
+ maxI64 = (1 << 63) - 1
+ maxI32 = (1 << 31) - 1
+ maxI16 = (1 << 15) - 1
+ maxI8 = (1 << 7) - 1
+
+ minI64 = -(1 << 63)
+ minI32 = -(1 << 31)
+ minI16 = -(1 << 15)
+ minI8 = -(1 << 7)
+)
+
+func cmp(left *big.Int, op string, right *big.Int) bool {
+ switch left.Cmp(right) {
+ case -1: // less than
+ return op == "<" || op == "<=" || op == "!="
+ case 0: // equal
+ return op == "==" || op == "<=" || op == ">="
+ case 1: // greater than
+ return op == ">" || op == ">=" || op == "!="
+ }
+ panic("unexpected comparison value")
+}
+
+func inRange(typ string, val *big.Int) bool {
+ min, max := &big.Int{}, &big.Int{}
+ switch typ {
+ case "uint64":
+ max = max.SetUint64(maxU64)
+ case "uint32":
+ max = max.SetUint64(maxU32)
+ case "uint16":
+ max = max.SetUint64(maxU16)
+ case "uint8":
+ max = max.SetUint64(maxU8)
+ case "int64":
+ min = min.SetInt64(minI64)
+ max = max.SetInt64(maxI64)
+ case "int32":
+ min = min.SetInt64(minI32)
+ max = max.SetInt64(maxI32)
+ case "int16":
+ min = min.SetInt64(minI16)
+ max = max.SetInt64(maxI16)
+ case "int8":
+ min = min.SetInt64(minI8)
+ max = max.SetInt64(maxI8)
+ default:
+ panic("unexpected type")
+ }
+ return cmp(min, "<=", val) && cmp(val, "<=", max)
+}
+
+func getValues(typ string) []*big.Int {
+ Uint := func(v uint64) *big.Int { return big.NewInt(0).SetUint64(v) }
+ Int := func(v int64) *big.Int { return big.NewInt(0).SetInt64(v) }
+ values := []*big.Int{
+ // limits
+ Uint(maxU64),
+ Uint(maxU64 - 1),
+ Uint(maxI64 + 1),
+ Uint(maxI64),
+ Uint(maxI64 - 1),
+ Uint(maxU32 + 1),
+ Uint(maxU32),
+ Uint(maxU32 - 1),
+ Uint(maxI32 + 1),
+ Uint(maxI32),
+ Uint(maxI32 - 1),
+ Uint(maxU16 + 1),
+ Uint(maxU16),
+ Uint(maxU16 - 1),
+ Uint(maxI16 + 1),
+ Uint(maxI16),
+ Uint(maxI16 - 1),
+ Uint(maxU8 + 1),
+ Uint(maxU8),
+ Uint(maxU8 - 1),
+ Uint(maxI8 + 1),
+ Uint(maxI8),
+ Uint(maxI8 - 1),
+ Uint(0),
+ Int(minI8 + 1),
+ Int(minI8),
+ Int(minI8 - 1),
+ Int(minI16 + 1),
+ Int(minI16),
+ Int(minI16 - 1),
+ Int(minI32 + 1),
+ Int(minI32),
+ Int(minI32 - 1),
+ Int(minI64 + 1),
+ Int(minI64),
+
+ // other possibly interesting values
+ Uint(1),
+ Int(-1),
+ Uint(0xff << 56),
+ Uint(0xff << 32),
+ Uint(0xff << 24),
+ }
+ sort.Slice(values, func(i, j int) bool { return values[i].Cmp(values[j]) == -1 })
+ var ret []*big.Int
+ for _, val := range values {
+ if !inRange(typ, val) {
+ continue
+ }
+ ret = append(ret, val)
+ }
+ return ret
+}
+
+func sigString(v *big.Int) string {
+ var t big.Int
+ t.Abs(v)
+ if v.Sign() == -1 {
+ return "neg" + t.String()
+ }
+ return t.String()
+}
+
+func main() {
+ types := []string{
+ "uint64", "uint32", "uint16", "uint8",
+ "int64", "int32", "int16", "int8",
+ }
+
+ w := new(bytes.Buffer)
+ fmt.Fprintf(w, "// Code generated by gen/cmpConstGen.go. DO NOT EDIT.\n\n")
+ fmt.Fprintf(w, "package main;\n")
+ fmt.Fprintf(w, "import (\"testing\"; \"reflect\"; \"runtime\";)\n")
+ fmt.Fprintf(w, "// results show the expected result for the elements left of, equal to and right of the index.\n")
+ fmt.Fprintf(w, "type result struct{l, e, r bool}\n")
+ fmt.Fprintf(w, "var (\n")
+ fmt.Fprintf(w, " eq = result{l: false, e: true, r: false}\n")
+ fmt.Fprintf(w, " ne = result{l: true, e: false, r: true}\n")
+ fmt.Fprintf(w, " lt = result{l: true, e: false, r: false}\n")
+ fmt.Fprintf(w, " le = result{l: true, e: true, r: false}\n")
+ fmt.Fprintf(w, " gt = result{l: false, e: false, r: true}\n")
+ fmt.Fprintf(w, " ge = result{l: false, e: true, r: true}\n")
+ fmt.Fprintf(w, ")\n")
+
+ operators := []struct{ op, name string }{
+ {"<", "lt"},
+ {"<=", "le"},
+ {">", "gt"},
+ {">=", "ge"},
+ {"==", "eq"},
+ {"!=", "ne"},
+ }
+
+ for _, typ := range types {
+ // generate a slice containing valid values for this type
+ fmt.Fprintf(w, "\n// %v tests\n", typ)
+ values := getValues(typ)
+ fmt.Fprintf(w, "var %v_vals = []%v{\n", typ, typ)
+ for _, val := range values {
+ fmt.Fprintf(w, "%v,\n", val.String())
+ }
+ fmt.Fprintf(w, "}\n")
+
+ // generate test functions
+ for _, r := range values {
+ // TODO: could also test constant on lhs.
+ sig := sigString(r)
+ for _, op := range operators {
+ // no need for go:noinline because the function is called indirectly
+ fmt.Fprintf(w, "func %v_%v_%v(x %v) bool { return x %v %v; }\n", op.name, sig, typ, typ, op.op, r.String())
+ }
+ }
+
+ // generate a table of test cases
+ fmt.Fprintf(w, "var %v_tests = []struct{\n", typ)
+ fmt.Fprintf(w, " idx int // index of the constant used\n")
+ fmt.Fprintf(w, " exp result // expected results\n")
+ fmt.Fprintf(w, " fn func(%v) bool\n", typ)
+ fmt.Fprintf(w, "}{\n")
+ for i, r := range values {
+ sig := sigString(r)
+ for _, op := range operators {
+ fmt.Fprintf(w, "{idx: %v,", i)
+ fmt.Fprintf(w, "exp: %v,", op.name)
+ fmt.Fprintf(w, "fn: %v_%v_%v},\n", op.name, sig, typ)
+ }
+ }
+ fmt.Fprintf(w, "}\n")
+ }
+
+ // emit the main function, looping over all test cases
+ fmt.Fprintf(w, "// TestComparisonsConst tests results for comparison operations against constants.\n")
+ fmt.Fprintf(w, "func TestComparisonsConst(t *testing.T) {\n")
+ for _, typ := range types {
+ fmt.Fprintf(w, "for i, test := range %v_tests {\n", typ)
+ fmt.Fprintf(w, " for j, x := range %v_vals {\n", typ)
+ fmt.Fprintf(w, " want := test.exp.l\n")
+ fmt.Fprintf(w, " if j == test.idx {\nwant = test.exp.e\n}")
+ fmt.Fprintf(w, " else if j > test.idx {\nwant = test.exp.r\n}\n")
+ fmt.Fprintf(w, " if test.fn(x) != want {\n")
+ fmt.Fprintf(w, " fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()\n")
+ fmt.Fprintf(w, " t.Errorf(\"test failed: %%v(%%v) != %%v [type=%v i=%%v j=%%v idx=%%v]\", fn, x, want, i, j, test.idx)\n", typ)
+ fmt.Fprintf(w, " }\n")
+ fmt.Fprintf(w, " }\n")
+ fmt.Fprintf(w, "}\n")
+ }
+ fmt.Fprintf(w, "}\n")
+
+ // gofmt result
+ b := w.Bytes()
+ src, err := format.Source(b)
+ if err != nil {
+ fmt.Printf("%s\n", b)
+ panic(err)
+ }
+
+ // write to file
+ err = ioutil.WriteFile("../cmpConst_test.go", src, 0666)
+ if err != nil {
+ log.Fatalf("can't write output: %v\n", err)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
new file mode 100644
index 0000000..2b8a331
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
@@ -0,0 +1,307 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This program generates a test to verify that the standard arithmetic
+// operators properly handle constant folding. The test file should be
+// generated with a known working version of go.
+// launch with `go run constFoldGen.go` a file called constFold_test.go
+// will be written into the grandparent directory containing the tests.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+)
+
+type op struct {
+ name, symbol string
+}
+type szD struct {
+ name string
+ sn string
+ u []uint64
+ i []int64
+}
+
+var szs []szD = []szD{
+ szD{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
+ szD{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+ -4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
+
+ szD{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
+ szD{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0,
+ 1, 0x7FFFFFFF}},
+
+ szD{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
+ szD{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}},
+
+ szD{name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
+ szD{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}},
+}
+
+var ops = []op{
+ op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mul", "*"},
+ op{"lsh", "<<"}, op{"rsh", ">>"}, op{"mod", "%"},
+}
+
+// compute the result of i op j, cast as type t.
+func ansU(i, j uint64, t, op string) string {
+ var ans uint64
+ switch op {
+ case "+":
+ ans = i + j
+ case "-":
+ ans = i - j
+ case "*":
+ ans = i * j
+ case "/":
+ if j != 0 {
+ ans = i / j
+ }
+ case "%":
+ if j != 0 {
+ ans = i % j
+ }
+ case "<<":
+ ans = i << j
+ case ">>":
+ ans = i >> j
+ }
+ switch t {
+ case "uint32":
+ ans = uint64(uint32(ans))
+ case "uint16":
+ ans = uint64(uint16(ans))
+ case "uint8":
+ ans = uint64(uint8(ans))
+ }
+ return fmt.Sprintf("%d", ans)
+}
+
+// compute the result of i op j, cast as type t.
+func ansS(i, j int64, t, op string) string {
+ var ans int64
+ switch op {
+ case "+":
+ ans = i + j
+ case "-":
+ ans = i - j
+ case "*":
+ ans = i * j
+ case "/":
+ if j != 0 {
+ ans = i / j
+ }
+ case "%":
+ if j != 0 {
+ ans = i % j
+ }
+ case "<<":
+ ans = i << uint64(j)
+ case ">>":
+ ans = i >> uint64(j)
+ }
+ switch t {
+ case "int32":
+ ans = int64(int32(ans))
+ case "int16":
+ ans = int64(int16(ans))
+ case "int8":
+ ans = int64(int8(ans))
+ }
+ return fmt.Sprintf("%d", ans)
+}
+
+func main() {
+ w := new(bytes.Buffer)
+ fmt.Fprintf(w, "// run\n")
+ fmt.Fprintf(w, "// Code generated by gen/constFoldGen.go. DO NOT EDIT.\n\n")
+ fmt.Fprintf(w, "package gc\n")
+ fmt.Fprintf(w, "import \"testing\"\n")
+
+ for _, s := range szs {
+ for _, o := range ops {
+ if o.symbol == "<<" || o.symbol == ">>" {
+ // shifts handled separately below, as they can have
+ // different types on the LHS and RHS.
+ continue
+ }
+ fmt.Fprintf(w, "func TestConstFold%s%s(t *testing.T) {\n", s.name, o.name)
+ fmt.Fprintf(w, "\tvar x, y, r %s\n", s.name)
+ // unsigned test cases
+ for _, c := range s.u {
+ fmt.Fprintf(w, "\tx = %d\n", c)
+ for _, d := range s.u {
+ if d == 0 && (o.symbol == "/" || o.symbol == "%") {
+ continue
+ }
+ fmt.Fprintf(w, "\ty = %d\n", d)
+ fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
+ want := ansU(c, d, s.name, o.symbol)
+ fmt.Fprintf(w, "\tif r != %s {\n", want)
+ fmt.Fprintf(w, "\t\tt.Errorf(\"%d %%s %d = %%d, want %s\", %q, r)\n", c, d, want, o.symbol)
+ fmt.Fprintf(w, "\t}\n")
+ }
+ }
+ // signed test cases
+ for _, c := range s.i {
+ fmt.Fprintf(w, "\tx = %d\n", c)
+ for _, d := range s.i {
+ if d == 0 && (o.symbol == "/" || o.symbol == "%") {
+ continue
+ }
+ fmt.Fprintf(w, "\ty = %d\n", d)
+ fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
+ want := ansS(c, d, s.name, o.symbol)
+ fmt.Fprintf(w, "\tif r != %s {\n", want)
+ fmt.Fprintf(w, "\t\tt.Errorf(\"%d %%s %d = %%d, want %s\", %q, r)\n", c, d, want, o.symbol)
+ fmt.Fprintf(w, "\t}\n")
+ }
+ }
+ fmt.Fprintf(w, "}\n")
+ }
+ }
+
+ // Special signed/unsigned cases for shifts
+ for _, ls := range szs {
+ for _, rs := range szs {
+ if rs.name[0] != 'u' {
+ continue
+ }
+ for _, o := range ops {
+ if o.symbol != "<<" && o.symbol != ">>" {
+ continue
+ }
+ fmt.Fprintf(w, "func TestConstFold%s%s%s(t *testing.T) {\n", ls.name, rs.name, o.name)
+ fmt.Fprintf(w, "\tvar x, r %s\n", ls.name)
+ fmt.Fprintf(w, "\tvar y %s\n", rs.name)
+ // unsigned LHS
+ for _, c := range ls.u {
+ fmt.Fprintf(w, "\tx = %d\n", c)
+ for _, d := range rs.u {
+ fmt.Fprintf(w, "\ty = %d\n", d)
+ fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
+ want := ansU(c, d, ls.name, o.symbol)
+ fmt.Fprintf(w, "\tif r != %s {\n", want)
+ fmt.Fprintf(w, "\t\tt.Errorf(\"%d %%s %d = %%d, want %s\", %q, r)\n", c, d, want, o.symbol)
+ fmt.Fprintf(w, "\t}\n")
+ }
+ }
+ // signed LHS
+ for _, c := range ls.i {
+ fmt.Fprintf(w, "\tx = %d\n", c)
+ for _, d := range rs.u {
+ fmt.Fprintf(w, "\ty = %d\n", d)
+ fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
+ want := ansS(c, int64(d), ls.name, o.symbol)
+ fmt.Fprintf(w, "\tif r != %s {\n", want)
+ fmt.Fprintf(w, "\t\tt.Errorf(\"%d %%s %d = %%d, want %s\", %q, r)\n", c, d, want, o.symbol)
+ fmt.Fprintf(w, "\t}\n")
+ }
+ }
+ fmt.Fprintf(w, "}\n")
+ }
+ }
+ }
+
+ // Constant folding for comparisons
+ for _, s := range szs {
+ fmt.Fprintf(w, "func TestConstFoldCompare%s(t *testing.T) {\n", s.name)
+ for _, x := range s.i {
+ for _, y := range s.i {
+ fmt.Fprintf(w, "\t{\n")
+ fmt.Fprintf(w, "\t\tvar x %s = %d\n", s.name, x)
+ fmt.Fprintf(w, "\t\tvar y %s = %d\n", s.name, y)
+ if x == y {
+ fmt.Fprintf(w, "\t\tif !(x == y) { t.Errorf(\"!(%%d == %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x == y { t.Errorf(\"%%d == %%d\", x, y) }\n")
+ }
+ if x != y {
+ fmt.Fprintf(w, "\t\tif !(x != y) { t.Errorf(\"!(%%d != %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x != y { t.Errorf(\"%%d != %%d\", x, y) }\n")
+ }
+ if x < y {
+ fmt.Fprintf(w, "\t\tif !(x < y) { t.Errorf(\"!(%%d < %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x < y { t.Errorf(\"%%d < %%d\", x, y) }\n")
+ }
+ if x > y {
+ fmt.Fprintf(w, "\t\tif !(x > y) { t.Errorf(\"!(%%d > %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x > y { t.Errorf(\"%%d > %%d\", x, y) }\n")
+ }
+ if x <= y {
+ fmt.Fprintf(w, "\t\tif !(x <= y) { t.Errorf(\"!(%%d <= %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x <= y { t.Errorf(\"%%d <= %%d\", x, y) }\n")
+ }
+ if x >= y {
+ fmt.Fprintf(w, "\t\tif !(x >= y) { t.Errorf(\"!(%%d >= %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x >= y { t.Errorf(\"%%d >= %%d\", x, y) }\n")
+ }
+ fmt.Fprintf(w, "\t}\n")
+ }
+ }
+ for _, x := range s.u {
+ for _, y := range s.u {
+ fmt.Fprintf(w, "\t{\n")
+ fmt.Fprintf(w, "\t\tvar x %s = %d\n", s.name, x)
+ fmt.Fprintf(w, "\t\tvar y %s = %d\n", s.name, y)
+ if x == y {
+ fmt.Fprintf(w, "\t\tif !(x == y) { t.Errorf(\"!(%%d == %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x == y { t.Errorf(\"%%d == %%d\", x, y) }\n")
+ }
+ if x != y {
+ fmt.Fprintf(w, "\t\tif !(x != y) { t.Errorf(\"!(%%d != %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x != y { t.Errorf(\"%%d != %%d\", x, y) }\n")
+ }
+ if x < y {
+ fmt.Fprintf(w, "\t\tif !(x < y) { t.Errorf(\"!(%%d < %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x < y { t.Errorf(\"%%d < %%d\", x, y) }\n")
+ }
+ if x > y {
+ fmt.Fprintf(w, "\t\tif !(x > y) { t.Errorf(\"!(%%d > %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x > y { t.Errorf(\"%%d > %%d\", x, y) }\n")
+ }
+ if x <= y {
+ fmt.Fprintf(w, "\t\tif !(x <= y) { t.Errorf(\"!(%%d <= %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x <= y { t.Errorf(\"%%d <= %%d\", x, y) }\n")
+ }
+ if x >= y {
+ fmt.Fprintf(w, "\t\tif !(x >= y) { t.Errorf(\"!(%%d >= %%d)\", x, y) }\n")
+ } else {
+ fmt.Fprintf(w, "\t\tif x >= y { t.Errorf(\"%%d >= %%d\", x, y) }\n")
+ }
+ fmt.Fprintf(w, "\t}\n")
+ }
+ }
+ fmt.Fprintf(w, "}\n")
+ }
+
+ // gofmt result
+ b := w.Bytes()
+ src, err := format.Source(b)
+ if err != nil {
+ fmt.Printf("%s\n", b)
+ panic(err)
+ }
+
+ // write to file
+ err = ioutil.WriteFile("../../constFold_test.go", src, 0666)
+ if err != nil {
+ log.Fatalf("can't write output: %v\n", err)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/copyGen.go b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
new file mode 100644
index 0000000..4567f2f
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
@@ -0,0 +1,121 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+)
+
+// This program generates tests to verify that copying operations
+// copy the data they are supposed to and clobber no adjacent values.
+
+// run as `go run copyGen.go`. A file called copy.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}
+
+var usizes = [...]int{2, 3, 4, 5, 6, 7}
+
+func main() {
+ w := new(bytes.Buffer)
+ fmt.Fprintf(w, "// Code generated by gen/copyGen.go. DO NOT EDIT.\n\n")
+ fmt.Fprintf(w, "package main\n")
+ fmt.Fprintf(w, "import \"testing\"\n")
+
+ for _, s := range sizes {
+ // type for test
+ fmt.Fprintf(w, "type T%d struct {\n", s)
+ fmt.Fprintf(w, " pre [8]byte\n")
+ fmt.Fprintf(w, " mid [%d]byte\n", s)
+ fmt.Fprintf(w, " post [8]byte\n")
+ fmt.Fprintf(w, "}\n")
+
+ // function being tested
+ fmt.Fprintf(w, "//go:noinline\n")
+ fmt.Fprintf(w, "func t%dcopy_ssa(y, x *[%d]byte) {\n", s, s)
+ fmt.Fprintf(w, " *y = *x\n")
+ fmt.Fprintf(w, "}\n")
+
+ // testing harness
+ fmt.Fprintf(w, "func testCopy%d(t *testing.T) {\n", s)
+ fmt.Fprintf(w, " a := T%d{[8]byte{201, 202, 203, 204, 205, 206, 207, 208},[%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "%d,", i%100)
+ }
+ fmt.Fprintf(w, "},[8]byte{211, 212, 213, 214, 215, 216, 217, 218}}\n")
+ fmt.Fprintf(w, " x := [%d]byte{", s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "%d,", 100+i%100)
+ }
+ fmt.Fprintf(w, "}\n")
+ fmt.Fprintf(w, " t%dcopy_ssa(&a.mid, &x)\n", s)
+ fmt.Fprintf(w, " want := T%d{[8]byte{201, 202, 203, 204, 205, 206, 207, 208},[%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "%d,", 100+i%100)
+ }
+ fmt.Fprintf(w, "},[8]byte{211, 212, 213, 214, 215, 216, 217, 218}}\n")
+ fmt.Fprintf(w, " if a != want {\n")
+ fmt.Fprintf(w, " t.Errorf(\"t%dcopy got=%%v, want %%v\\n\", a, want)\n", s)
+ fmt.Fprintf(w, " }\n")
+ fmt.Fprintf(w, "}\n")
+ }
+
+ for _, s := range usizes {
+ // function being tested
+ fmt.Fprintf(w, "//go:noinline\n")
+ fmt.Fprintf(w, "func tu%dcopy_ssa(docopy bool, data [%d]byte, x *[%d]byte) {\n", s, s, s)
+ fmt.Fprintf(w, " if docopy {\n")
+ fmt.Fprintf(w, " *x = data\n")
+ fmt.Fprintf(w, " }\n")
+ fmt.Fprintf(w, "}\n")
+
+ // testing harness
+ fmt.Fprintf(w, "func testUnalignedCopy%d(t *testing.T) {\n", s)
+ fmt.Fprintf(w, " var a [%d]byte\n", s)
+ fmt.Fprintf(w, " t%d := [%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, " %d,", s+i)
+ }
+ fmt.Fprintf(w, "}\n")
+ fmt.Fprintf(w, " tu%dcopy_ssa(true, t%d, &a)\n", s, s)
+ fmt.Fprintf(w, " want%d := [%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, " %d,", s+i)
+ }
+ fmt.Fprintf(w, "}\n")
+ fmt.Fprintf(w, " if a != want%d {\n", s)
+ fmt.Fprintf(w, " t.Errorf(\"tu%dcopy got=%%v, want %%v\\n\", a, want%d)\n", s, s)
+ fmt.Fprintf(w, " }\n")
+ fmt.Fprintf(w, "}\n")
+ }
+
+ // boilerplate at end
+ fmt.Fprintf(w, "func TestCopy(t *testing.T) {\n")
+ for _, s := range sizes {
+ fmt.Fprintf(w, " testCopy%d(t)\n", s)
+ }
+ for _, s := range usizes {
+ fmt.Fprintf(w, " testUnalignedCopy%d(t)\n", s)
+ }
+ fmt.Fprintf(w, "}\n")
+
+ // gofmt result
+ b := w.Bytes()
+ src, err := format.Source(b)
+ if err != nil {
+ fmt.Printf("%s\n", b)
+ panic(err)
+ }
+
+ // write to file
+ err = ioutil.WriteFile("../copy_test.go", src, 0666)
+ if err != nil {
+ log.Fatalf("can't write output: %v\n", err)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
new file mode 100644
index 0000000..7056730
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
@@ -0,0 +1,143 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+)
+
+// This program generates tests to verify that zeroing operations
+// zero the data they are supposed to and clobber no adjacent values.
+
+// run as `go run zeroGen.go`. A file called zero.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}
+var usizes = [...]int{8, 16, 24, 32, 64, 256}
+
+func main() {
+ w := new(bytes.Buffer)
+ fmt.Fprintf(w, "// Code generated by gen/zeroGen.go. DO NOT EDIT.\n\n")
+ fmt.Fprintf(w, "package main\n")
+ fmt.Fprintf(w, "import \"testing\"\n")
+
+ for _, s := range sizes {
+ // type for test
+ fmt.Fprintf(w, "type Z%d struct {\n", s)
+ fmt.Fprintf(w, " pre [8]byte\n")
+ fmt.Fprintf(w, " mid [%d]byte\n", s)
+ fmt.Fprintf(w, " post [8]byte\n")
+ fmt.Fprintf(w, "}\n")
+
+ // function being tested
+ fmt.Fprintf(w, "//go:noinline\n")
+ fmt.Fprintf(w, "func zero%d_ssa(x *[%d]byte) {\n", s, s)
+ fmt.Fprintf(w, " *x = [%d]byte{}\n", s)
+ fmt.Fprintf(w, "}\n")
+
+ // testing harness
+ fmt.Fprintf(w, "func testZero%d(t *testing.T) {\n", s)
+ fmt.Fprintf(w, " a := Z%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "255,")
+ }
+ fmt.Fprintf(w, "},[8]byte{255,255,255,255,255,255,255,255}}\n")
+ fmt.Fprintf(w, " zero%d_ssa(&a.mid)\n", s)
+ fmt.Fprintf(w, " want := Z%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "0,")
+ }
+ fmt.Fprintf(w, "},[8]byte{255,255,255,255,255,255,255,255}}\n")
+ fmt.Fprintf(w, " if a != want {\n")
+ fmt.Fprintf(w, " t.Errorf(\"zero%d got=%%v, want %%v\\n\", a, want)\n", s)
+ fmt.Fprintf(w, " }\n")
+ fmt.Fprintf(w, "}\n")
+ }
+
+ for _, s := range usizes {
+ // type for test
+ fmt.Fprintf(w, "type Z%du1 struct {\n", s)
+ fmt.Fprintf(w, " b bool\n")
+ fmt.Fprintf(w, " val [%d]byte\n", s)
+ fmt.Fprintf(w, "}\n")
+
+ fmt.Fprintf(w, "type Z%du2 struct {\n", s)
+ fmt.Fprintf(w, " i uint16\n")
+ fmt.Fprintf(w, " val [%d]byte\n", s)
+ fmt.Fprintf(w, "}\n")
+
+ // function being tested
+ fmt.Fprintf(w, "//go:noinline\n")
+ fmt.Fprintf(w, "func zero%du1_ssa(t *Z%du1) {\n", s, s)
+ fmt.Fprintf(w, " t.val = [%d]byte{}\n", s)
+ fmt.Fprintf(w, "}\n")
+
+ // function being tested
+ fmt.Fprintf(w, "//go:noinline\n")
+ fmt.Fprintf(w, "func zero%du2_ssa(t *Z%du2) {\n", s, s)
+ fmt.Fprintf(w, " t.val = [%d]byte{}\n", s)
+ fmt.Fprintf(w, "}\n")
+
+ // testing harness
+ fmt.Fprintf(w, "func testZero%du(t *testing.T) {\n", s)
+ fmt.Fprintf(w, " a := Z%du1{false, [%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "255,")
+ }
+ fmt.Fprintf(w, "}}\n")
+ fmt.Fprintf(w, " zero%du1_ssa(&a)\n", s)
+ fmt.Fprintf(w, " want := Z%du1{false, [%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "0,")
+ }
+ fmt.Fprintf(w, "}}\n")
+ fmt.Fprintf(w, " if a != want {\n")
+ fmt.Fprintf(w, " t.Errorf(\"zero%du2 got=%%v, want %%v\\n\", a, want)\n", s)
+ fmt.Fprintf(w, " }\n")
+ fmt.Fprintf(w, " b := Z%du2{15, [%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "255,")
+ }
+ fmt.Fprintf(w, "}}\n")
+ fmt.Fprintf(w, " zero%du2_ssa(&b)\n", s)
+ fmt.Fprintf(w, " wantb := Z%du2{15, [%d]byte{", s, s)
+ for i := 0; i < s; i++ {
+ fmt.Fprintf(w, "0,")
+ }
+ fmt.Fprintf(w, "}}\n")
+ fmt.Fprintf(w, " if b != wantb {\n")
+ fmt.Fprintf(w, " t.Errorf(\"zero%du2 got=%%v, want %%v\\n\", b, wantb)\n", s)
+ fmt.Fprintf(w, " }\n")
+ fmt.Fprintf(w, "}\n")
+ }
+
+ // boilerplate at end
+ fmt.Fprintf(w, "func TestZero(t *testing.T) {\n")
+ for _, s := range sizes {
+ fmt.Fprintf(w, " testZero%d(t)\n", s)
+ }
+ for _, s := range usizes {
+ fmt.Fprintf(w, " testZero%du(t)\n", s)
+ }
+ fmt.Fprintf(w, "}\n")
+
+ // gofmt result
+ b := w.Bytes()
+ src, err := format.Source(b)
+ if err != nil {
+ fmt.Printf("%s\n", b)
+ panic(err)
+ }
+
+ // write to file
+ err = ioutil.WriteFile("../zero_test.go", src, 0666)
+ if err != nil {
+ log.Fatalf("can't write output: %v\n", err)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/loadstore_test.go b/src/cmd/compile/internal/gc/testdata/loadstore_test.go
new file mode 100644
index 0000000..57571f5
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/loadstore_test.go
@@ -0,0 +1,204 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests load/store ordering
+
+package main
+
+import "testing"
+
+// testLoadStoreOrder tests for reordering of stores/loads.
+func testLoadStoreOrder(t *testing.T) {
+ z := uint32(1000)
+ if testLoadStoreOrder_ssa(&z, 100) == 0 {
+ t.Errorf("testLoadStoreOrder failed")
+ }
+}
+
+//go:noinline
+func testLoadStoreOrder_ssa(z *uint32, prec uint) int {
+ old := *z // load
+ *z = uint32(prec) // store
+ if *z < old { // load
+ return 1
+ }
+ return 0
+}
+
+func testStoreSize(t *testing.T) {
+ a := [4]uint16{11, 22, 33, 44}
+ testStoreSize_ssa(&a[0], &a[2], 77)
+ want := [4]uint16{77, 22, 33, 44}
+ if a != want {
+ t.Errorf("testStoreSize failed. want = %d, got = %d", want, a)
+ }
+}
+
+//go:noinline
+func testStoreSize_ssa(p *uint16, q *uint16, v uint32) {
+ // Test to make sure that (Store ptr (Trunc32to16 val) mem)
+ // does not end up as a 32-bit store. It must stay a 16 bit store
+ // even when Trunc32to16 is rewritten to be a nop.
+ // To ensure that we get rewrite the Trunc32to16 before
+ // we rewrite the Store, we force the truncate into an
+ // earlier basic block by using it on both branches.
+ w := uint16(v)
+ if p != nil {
+ *p = w
+ } else {
+ *q = w
+ }
+}
+
+//go:noinline
+func testExtStore_ssa(p *byte, b bool) int {
+ x := *p
+ *p = 7
+ if b {
+ return int(x)
+ }
+ return 0
+}
+
+func testExtStore(t *testing.T) {
+ const start = 8
+ var b byte = start
+ if got := testExtStore_ssa(&b, true); got != start {
+ t.Errorf("testExtStore failed. want = %d, got = %d", start, got)
+ }
+}
+
+var b int
+
+// testDeadStorePanic_ssa ensures that we don't optimize away stores
+// that could be read by after recover(). Modeled after fixedbugs/issue1304.
+//go:noinline
+func testDeadStorePanic_ssa(a int) (r int) {
+ defer func() {
+ recover()
+ r = a
+ }()
+ a = 2 // store
+ b := a - a // optimized to zero
+ c := 4
+ a = c / b // store, but panics
+ a = 3 // store
+ r = a
+ return
+}
+
+func testDeadStorePanic(t *testing.T) {
+ if want, got := 2, testDeadStorePanic_ssa(1); want != got {
+ t.Errorf("testDeadStorePanic failed. want = %d, got = %d", want, got)
+ }
+}
+
+//go:noinline
+func loadHitStore8(x int8, p *int8) int32 {
+ x *= x // try to trash high bits (arch-dependent)
+ *p = x // store
+ return int32(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStoreU8(x uint8, p *uint8) uint32 {
+ x *= x // try to trash high bits (arch-dependent)
+ *p = x // store
+ return uint32(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStore16(x int16, p *int16) int32 {
+ x *= x // try to trash high bits (arch-dependent)
+ *p = x // store
+ return int32(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStoreU16(x uint16, p *uint16) uint32 {
+ x *= x // try to trash high bits (arch-dependent)
+ *p = x // store
+ return uint32(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStore32(x int32, p *int32) int64 {
+ x *= x // try to trash high bits (arch-dependent)
+ *p = x // store
+ return int64(*p) // load and cast
+}
+
+//go:noinline
+func loadHitStoreU32(x uint32, p *uint32) uint64 {
+ x *= x // try to trash high bits (arch-dependent)
+ *p = x // store
+ return uint64(*p) // load and cast
+}
+
+func testLoadHitStore(t *testing.T) {
+ // Test that sign/zero extensions are kept when a load-hit-store
+ // is replaced by a register-register move.
+ {
+ var in int8 = (1 << 6) + 1
+ var p int8
+ got := loadHitStore8(in, &p)
+ want := int32(in * in)
+ if got != want {
+ t.Errorf("testLoadHitStore (int8) failed. want = %d, got = %d", want, got)
+ }
+ }
+ {
+ var in uint8 = (1 << 6) + 1
+ var p uint8
+ got := loadHitStoreU8(in, &p)
+ want := uint32(in * in)
+ if got != want {
+ t.Errorf("testLoadHitStore (uint8) failed. want = %d, got = %d", want, got)
+ }
+ }
+ {
+ var in int16 = (1 << 10) + 1
+ var p int16
+ got := loadHitStore16(in, &p)
+ want := int32(in * in)
+ if got != want {
+ t.Errorf("testLoadHitStore (int16) failed. want = %d, got = %d", want, got)
+ }
+ }
+ {
+ var in uint16 = (1 << 10) + 1
+ var p uint16
+ got := loadHitStoreU16(in, &p)
+ want := uint32(in * in)
+ if got != want {
+ t.Errorf("testLoadHitStore (uint16) failed. want = %d, got = %d", want, got)
+ }
+ }
+ {
+ var in int32 = (1 << 30) + 1
+ var p int32
+ got := loadHitStore32(in, &p)
+ want := int64(in * in)
+ if got != want {
+ t.Errorf("testLoadHitStore (int32) failed. want = %d, got = %d", want, got)
+ }
+ }
+ {
+ var in uint32 = (1 << 30) + 1
+ var p uint32
+ got := loadHitStoreU32(in, &p)
+ want := uint64(in * in)
+ if got != want {
+ t.Errorf("testLoadHitStore (uint32) failed. want = %d, got = %d", want, got)
+ }
+ }
+}
+
+func TestLoadStore(t *testing.T) {
+ testLoadStoreOrder(t)
+ testStoreSize(t)
+ testExtStore(t)
+ testDeadStorePanic(t)
+ testLoadHitStore(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/map_test.go b/src/cmd/compile/internal/gc/testdata/map_test.go
new file mode 100644
index 0000000..71dc820
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/map_test.go
@@ -0,0 +1,37 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// map.go tests map operations.
+package main
+
+import "testing"
+
+//go:noinline
+func lenMap_ssa(v map[int]int) int {
+ return len(v)
+}
+
+func testLenMap(t *testing.T) {
+
+ v := make(map[int]int)
+ v[0] = 0
+ v[1] = 0
+ v[2] = 0
+
+ if want, got := 3, lenMap_ssa(v); got != want {
+ t.Errorf("expected len(map) = %d, got %d", want, got)
+ }
+}
+
+func testLenNilMap(t *testing.T) {
+
+ var v map[int]int
+ if want, got := 0, lenMap_ssa(v); got != want {
+ t.Errorf("expected len(nil) = %d, got %d", want, got)
+ }
+}
+func TestMap(t *testing.T) {
+ testLenMap(t)
+ testLenNilMap(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/namedReturn_test.go b/src/cmd/compile/internal/gc/testdata/namedReturn_test.go
new file mode 100644
index 0000000..b07e225
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/namedReturn_test.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.
+
+// This test makes sure that naming named
+// return variables in a return statement works.
+// See issue #14904.
+
+package main
+
+import (
+ "runtime"
+ "testing"
+)
+
+// Our heap-allocated object that will be GC'd incorrectly.
+// Note that we always check the second word because that's
+// where 0xdeaddeaddeaddead is written.
+type B [4]int
+
+// small (SSAable) array
+type A1 [3]*B
+
+//go:noinline
+func f1() (t A1) {
+ t[0] = &B{91, 92, 93, 94}
+ runtime.GC()
+ return t
+}
+
+// large (non-SSAable) array
+type A2 [8]*B
+
+//go:noinline
+func f2() (t A2) {
+ t[0] = &B{91, 92, 93, 94}
+ runtime.GC()
+ return t
+}
+
+// small (SSAable) struct
+type A3 struct {
+ a, b, c *B
+}
+
+//go:noinline
+func f3() (t A3) {
+ t.a = &B{91, 92, 93, 94}
+ runtime.GC()
+ return t
+}
+
+// large (non-SSAable) struct
+type A4 struct {
+ a, b, c, d, e, f *B
+}
+
+//go:noinline
+func f4() (t A4) {
+ t.a = &B{91, 92, 93, 94}
+ runtime.GC()
+ return t
+}
+
+var sink *B
+
+func f5() int {
+ b := &B{91, 92, 93, 94}
+ t := A4{b, nil, nil, nil, nil, nil}
+ sink = b // make sure b is heap allocated ...
+ sink = nil // ... but not live
+ runtime.GC()
+ t = t
+ return t.a[1]
+}
+
+func TestNamedReturn(t *testing.T) {
+ if v := f1()[0][1]; v != 92 {
+ t.Errorf("f1()[0][1]=%d, want 92\n", v)
+ }
+ if v := f2()[0][1]; v != 92 {
+ t.Errorf("f2()[0][1]=%d, want 92\n", v)
+ }
+ if v := f3().a[1]; v != 92 {
+ t.Errorf("f3().a[1]=%d, want 92\n", v)
+ }
+ if v := f4().a[1]; v != 92 {
+ t.Errorf("f4().a[1]=%d, want 92\n", v)
+ }
+ if v := f5(); v != 92 {
+ t.Errorf("f5()=%d, want 92\n", v)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/phi_test.go b/src/cmd/compile/internal/gc/testdata/phi_test.go
new file mode 100644
index 0000000..c8a73ff
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/phi_test.go
@@ -0,0 +1,99 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Test to make sure spills of cast-shortened values
+// don't end up spilling the pre-shortened size instead
+// of the post-shortened size.
+
+import (
+ "runtime"
+ "testing"
+)
+
+var data1 [26]int32
+var data2 [26]int64
+
+func init() {
+ for i := 0; i < 26; i++ {
+ // If we spill all 8 bytes of this datum, the 1 in the high-order 4 bytes
+ // will overwrite some other variable in the stack frame.
+ data2[i] = 0x100000000
+ }
+}
+
+func foo() int32 {
+ var a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int32
+ if always {
+ a = data1[0]
+ b = data1[1]
+ c = data1[2]
+ d = data1[3]
+ e = data1[4]
+ f = data1[5]
+ g = data1[6]
+ h = data1[7]
+ i = data1[8]
+ j = data1[9]
+ k = data1[10]
+ l = data1[11]
+ m = data1[12]
+ n = data1[13]
+ o = data1[14]
+ p = data1[15]
+ q = data1[16]
+ r = data1[17]
+ s = data1[18]
+ t = data1[19]
+ u = data1[20]
+ v = data1[21]
+ w = data1[22]
+ x = data1[23]
+ y = data1[24]
+ z = data1[25]
+ } else {
+ a = int32(data2[0])
+ b = int32(data2[1])
+ c = int32(data2[2])
+ d = int32(data2[3])
+ e = int32(data2[4])
+ f = int32(data2[5])
+ g = int32(data2[6])
+ h = int32(data2[7])
+ i = int32(data2[8])
+ j = int32(data2[9])
+ k = int32(data2[10])
+ l = int32(data2[11])
+ m = int32(data2[12])
+ n = int32(data2[13])
+ o = int32(data2[14])
+ p = int32(data2[15])
+ q = int32(data2[16])
+ r = int32(data2[17])
+ s = int32(data2[18])
+ t = int32(data2[19])
+ u = int32(data2[20])
+ v = int32(data2[21])
+ w = int32(data2[22])
+ x = int32(data2[23])
+ y = int32(data2[24])
+ z = int32(data2[25])
+ }
+ // Lots of phis of the form phi(int32,int64) of type int32 happen here.
+ // Some will be stack phis. For those stack phis, make sure the spill
+ // of the second argument uses the phi's width (4 bytes), not its width
+ // (8 bytes). Otherwise, a random stack slot gets clobbered.
+
+ runtime.Gosched()
+ return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w + x + y + z
+}
+
+func TestPhi(t *testing.T) {
+ want := int32(0)
+ got := foo()
+ if got != want {
+ t.Fatalf("want %d, got %d\n", want, got)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/regalloc_test.go b/src/cmd/compile/internal/gc/testdata/regalloc_test.go
new file mode 100644
index 0000000..577f8e7
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/regalloc_test.go
@@ -0,0 +1,50 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests phi implementation
+
+package main
+
+import "testing"
+
+func phiOverwrite_ssa() int {
+ var n int
+ for i := 0; i < 10; i++ {
+ if i == 6 {
+ break
+ }
+ n = i
+ }
+ return n
+}
+
+func phiOverwrite(t *testing.T) {
+ want := 5
+ got := phiOverwrite_ssa()
+ if got != want {
+ t.Errorf("phiOverwrite_ssa()= %d, got %d", want, got)
+ }
+}
+
+func phiOverwriteBig_ssa() int {
+ var a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int
+ a = 1
+ for idx := 0; idx < 26; idx++ {
+ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z = b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a
+ }
+ return a*1 + b*2 + c*3 + d*4 + e*5 + f*6 + g*7 + h*8 + i*9 + j*10 + k*11 + l*12 + m*13 + n*14 + o*15 + p*16 + q*17 + r*18 + s*19 + t*20 + u*21 + v*22 + w*23 + x*24 + y*25 + z*26
+}
+
+func phiOverwriteBig(t *testing.T) {
+ want := 1
+ got := phiOverwriteBig_ssa()
+ if got != want {
+ t.Errorf("phiOverwriteBig_ssa()= %d, got %d", want, got)
+ }
+}
+
+func TestRegalloc(t *testing.T) {
+ phiOverwrite(t)
+ phiOverwriteBig(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/reproducible/issue20272.go b/src/cmd/compile/internal/gc/testdata/reproducible/issue20272.go
new file mode 100644
index 0000000..3db0b8a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/reproducible/issue20272.go
@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+var (
+ i0 uint8
+ b0 byte
+
+ i1 *uint8
+ b1 *byte
+
+ i2 **uint8
+ b2 **byte
+
+ i3 ***uint8
+ b3 ***byte
+
+ i4 ****uint8
+ b4 ****byte
+
+ i5 *****uint8
+ b5 *****byte
+
+ i6 ******uint8
+ b6 ******byte
+
+ i7 *******uint8
+ b7 *******byte
+
+ i8 ********uint8
+ b8 ********byte
+)
diff --git a/src/cmd/compile/internal/gc/testdata/reproducible/issue27013.go b/src/cmd/compile/internal/gc/testdata/reproducible/issue27013.go
new file mode 100644
index 0000000..817f4a6
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/reproducible/issue27013.go
@@ -0,0 +1,15 @@
+// Copyright 2018 The Go Authors. 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 A(arg interface{}) {
+ _ = arg.(interface{ Func() int32 })
+ _ = arg.(interface{ Func() int32 })
+ _ = arg.(interface{ Func() int32 })
+ _ = arg.(interface{ Func() int32 })
+ _ = arg.(interface{ Func() int32 })
+ _ = arg.(interface{ Func() int32 })
+ _ = arg.(interface{ Func() int32 })
+}
diff --git a/src/cmd/compile/internal/gc/testdata/reproducible/issue30202.go b/src/cmd/compile/internal/gc/testdata/reproducible/issue30202.go
new file mode 100644
index 0000000..7b5de2c
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/reproducible/issue30202.go
@@ -0,0 +1,17 @@
+// Copyright 2019 The Go Authors. 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 A(x interface {
+ X() int
+}) int {
+ return x.X()
+}
+
+func B(x interface {
+ X() int
+}) int {
+ return x.X()
+}
diff --git a/src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go b/src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go
new file mode 100644
index 0000000..db5ca7d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go
@@ -0,0 +1,70 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package issue38068
+
+// A type with a couple of inlinable, non-pointer-receiver methods
+// that have params and local variables.
+type A struct {
+ s string
+ next *A
+ prev *A
+}
+
+// Inlinable, value-received method with locals and parms.
+func (a A) double(x string, y int) string {
+ if y == 191 {
+ a.s = ""
+ }
+ q := a.s + "a"
+ r := a.s + "b"
+ return q + r
+}
+
+// Inlinable, value-received method with locals and parms.
+func (a A) triple(x string, y int) string {
+ q := a.s
+ if y == 998877 {
+ a.s = x
+ }
+ r := a.s + a.s
+ return q + r
+}
+
+type methods struct {
+ m1 func(a *A, x string, y int) string
+ m2 func(a *A, x string, y int) string
+}
+
+// Now a function that makes references to the methods via pointers,
+// which should trigger the wrapper generation.
+func P(a *A, ms *methods) {
+ if a != nil {
+ defer func() { println("done") }()
+ }
+ println(ms.m1(a, "a", 2))
+ println(ms.m2(a, "b", 3))
+}
+
+func G(x *A, n int) {
+ if n <= 0 {
+ println(n)
+ return
+ }
+ // Address-taken local of type A, which will insure that the
+ // compiler's dtypesym() routine will create a method wrapper.
+ var a, b A
+ a.next = x
+ a.prev = &b
+ x = &a
+ G(x, n-2)
+}
+
+var M methods
+
+func F() {
+ M.m1 = (*A).double
+ M.m2 = (*A).triple
+ G(nil, 100)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/short_test.go b/src/cmd/compile/internal/gc/testdata/short_test.go
new file mode 100644
index 0000000..7a743b5
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/short_test.go
@@ -0,0 +1,57 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests short circuiting.
+
+package main
+
+import "testing"
+
+func and_ssa(arg1, arg2 bool) bool {
+ return arg1 && rightCall(arg2)
+}
+
+func or_ssa(arg1, arg2 bool) bool {
+ return arg1 || rightCall(arg2)
+}
+
+var rightCalled bool
+
+//go:noinline
+func rightCall(v bool) bool {
+ rightCalled = true
+ return v
+ panic("unreached")
+}
+
+func testAnd(t *testing.T, arg1, arg2, wantRes bool) {
+ testShortCircuit(t, "AND", arg1, arg2, and_ssa, arg1, wantRes)
+}
+func testOr(t *testing.T, arg1, arg2, wantRes bool) {
+ testShortCircuit(t, "OR", arg1, arg2, or_ssa, !arg1, wantRes)
+}
+
+func testShortCircuit(t *testing.T, opName string, arg1, arg2 bool, fn func(bool, bool) bool, wantRightCall, wantRes bool) {
+ rightCalled = false
+ got := fn(arg1, arg2)
+ if rightCalled != wantRightCall {
+ t.Errorf("failed for %t %s %t; rightCalled=%t want=%t", arg1, opName, arg2, rightCalled, wantRightCall)
+ }
+ if wantRes != got {
+ t.Errorf("failed for %t %s %t; res=%t want=%t", arg1, opName, arg2, got, wantRes)
+ }
+}
+
+// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting.
+func TestShortCircuit(t *testing.T) {
+ testAnd(t, false, false, false)
+ testAnd(t, false, true, false)
+ testAnd(t, true, false, false)
+ testAnd(t, true, true, true)
+
+ testOr(t, false, false, false)
+ testOr(t, false, true, true)
+ testOr(t, true, false, true)
+ testOr(t, true, true, true)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/slice_test.go b/src/cmd/compile/internal/gc/testdata/slice_test.go
new file mode 100644
index 0000000..c134578
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/slice_test.go
@@ -0,0 +1,46 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This test makes sure that t.s = t.s[0:x] doesn't write
+// either the slice pointer or the capacity.
+// See issue #14855.
+
+package main
+
+import "testing"
+
+const N = 1000000
+
+type X struct {
+ s []int
+}
+
+func TestSlice(t *testing.T) {
+ done := make(chan struct{})
+ a := make([]int, N+10)
+
+ x := &X{a}
+
+ go func() {
+ for i := 0; i < N; i++ {
+ x.s = x.s[1:9]
+ }
+ done <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < N; i++ {
+ x.s = x.s[0:8] // should only write len
+ }
+ done <- struct{}{}
+ }()
+ <-done
+ <-done
+
+ if cap(x.s) != cap(a)-N {
+ t.Errorf("wanted cap=%d, got %d\n", cap(a)-N, cap(x.s))
+ }
+ if &x.s[0] != &a[N] {
+ t.Errorf("wanted ptr=%p, got %p\n", &a[N], &x.s[0])
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/sqrtConst_test.go b/src/cmd/compile/internal/gc/testdata/sqrtConst_test.go
new file mode 100644
index 0000000..5b7a149
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/sqrtConst_test.go
@@ -0,0 +1,50 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "math"
+ "testing"
+)
+
+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))},
+}
+
+func TestSqrtConst(t *testing.T) {
+ for _, test := range tests {
+ if test.got != test.want {
+ t.Errorf("%s: math.Sqrt(%f): got %f, want %f\n", test.name, test.in, test.got, test.want)
+ }
+ }
+ for _, test := range nanTests {
+ if math.IsNaN(test.got) != true {
+ t.Errorf("%s: math.Sqrt(%f): got %f, want NaN\n", test.name, test.in, test.got)
+ }
+ }
+ if got := math.Sqrt(math.Inf(1)); !math.IsInf(got, 1) {
+ t.Errorf("math.Sqrt(+Inf), got %f, want +Inf\n", got)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/string_test.go b/src/cmd/compile/internal/gc/testdata/string_test.go
new file mode 100644
index 0000000..5d086f0
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/string_test.go
@@ -0,0 +1,207 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// string_ssa.go tests string operations.
+package main
+
+import "testing"
+
+//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(t *testing.T) {
+ 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, test := range tests {
+ if got := test.fn(test.s, test.low, test.high); test.want != got {
+ t.Errorf("#%d %s[%d,%d] = %s, want %s", i, test.s, test.low, test.high, got, test.want)
+ }
+ }
+}
+
+type prefix struct {
+ prefix string
+}
+
+func (p *prefix) slice_ssa() {
+ p.prefix = p.prefix[:3]
+}
+
+//go:noinline
+func testStructSlice(t *testing.T) {
+ p := &prefix{"prefix"}
+ p.slice_ssa()
+ if "pre" != p.prefix {
+ t.Errorf("wrong field slice: wanted %s got %s", "pre", p.prefix)
+ }
+}
+
+func testStringSlicePanic(t *testing.T) {
+ defer func() {
+ if r := recover(); r != nil {
+ //println("panicked as expected")
+ }
+ }()
+
+ str := "foobar"
+ t.Errorf("got %s and expected to panic, but didn't", testStringSlice12_ssa(str, 3, 9))
+}
+
+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(t *testing.T) {
+ tests := []struct {
+ i int
+ want string
+ }{
+ {0, "Below"},
+ {1, "Exact"},
+ {2, "Above"},
+ }
+
+ for i, test := range tests {
+ if got := testSmallIndexType_ssa(test.i); got != test.want {
+ t.Errorf("#%d got %s wanted %s", i, got, test.want)
+ }
+ }
+}
+
+//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(t *testing.T) {
+ 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, test := range tests {
+ if got := testInt64Index_ssa(str, test.i); got != test.b {
+ t.Errorf("#%d got %d wanted %d", i, got, test.b)
+ }
+ if got := testInt64Slice_ssa(str, test.i, test.j); got != test.s {
+ t.Errorf("#%d got %s wanted %s", i, got, test.s)
+ }
+ }
+}
+
+func testInt64IndexPanic(t *testing.T) {
+ defer func() {
+ if r := recover(); r != nil {
+ //println("panicked as expected")
+ }
+ }()
+
+ str := "foobar"
+ t.Errorf("got %d and expected to panic, but didn't", testInt64Index_ssa(str, 1<<32+1))
+}
+
+func testInt64SlicePanic(t *testing.T) {
+ defer func() {
+ if r := recover(); r != nil {
+ //println("panicked as expected")
+ }
+ }()
+
+ str := "foobar"
+ t.Errorf("got %s and expected to panic, but didn't", testInt64Slice_ssa(str, 1<<32, 1<<32+1))
+}
+
+//go:noinline
+func testStringElem_ssa(s string, i int) byte {
+ return s[i]
+}
+
+func testStringElem(t *testing.T) {
+ tests := []struct {
+ s string
+ i int
+ n byte
+ }{
+ {"foobar", 3, 98},
+ {"foobar", 0, 102},
+ {"foobar", 5, 114},
+ }
+ for _, test := range tests {
+ if got := testStringElem_ssa(test.s, test.i); got != test.n {
+ t.Errorf("testStringElem \"%s\"[%d] = %d, wanted %d", test.s, test.i, got, test.n)
+ }
+ }
+}
+
+//go:noinline
+func testStringElemConst_ssa(i int) byte {
+ s := "foobar"
+ return s[i]
+}
+
+func testStringElemConst(t *testing.T) {
+ if got := testStringElemConst_ssa(3); got != 98 {
+ t.Errorf("testStringElemConst= %d, wanted 98", got)
+ }
+}
+
+func TestString(t *testing.T) {
+ testStringSlice(t)
+ testStringSlicePanic(t)
+ testStructSlice(t)
+ testSmallIndexType(t)
+ testStringElem(t)
+ testStringElemConst(t)
+ testInt64Index(t)
+ testInt64IndexPanic(t)
+ testInt64SlicePanic(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/unsafe_test.go b/src/cmd/compile/internal/gc/testdata/unsafe_test.go
new file mode 100644
index 0000000..37599d3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/unsafe_test.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.
+
+package main
+
+import (
+ "runtime"
+ "testing"
+ "unsafe"
+)
+
+// global pointer slot
+var a *[8]uint
+
+// unfoldable true
+var always = true
+
+// Test to make sure that a pointer value which is alive
+// across a call is retained, even when there are matching
+// conversions to/from uintptr around the call.
+// We arrange things very carefully to have to/from
+// conversions on either side of the call which cannot be
+// combined with any other conversions.
+func f_ssa() *[8]uint {
+ // Make x a uintptr pointing to where a points.
+ var x uintptr
+ if always {
+ x = uintptr(unsafe.Pointer(a))
+ } else {
+ x = 0
+ }
+ // Clobber the global pointer. The only live ref
+ // to the allocated object is now x.
+ a = nil
+
+ // Convert to pointer so it should hold
+ // the object live across GC call.
+ p := unsafe.Pointer(x)
+
+ // Call gc.
+ runtime.GC()
+
+ // Convert back to uintptr.
+ y := uintptr(p)
+
+ // Mess with y so that the subsequent cast
+ // to unsafe.Pointer can't be combined with the
+ // uintptr cast above.
+ var z uintptr
+ if always {
+ z = y
+ } else {
+ z = 0
+ }
+ return (*[8]uint)(unsafe.Pointer(z))
+}
+
+// g_ssa is the same as f_ssa, but with a bit of pointer
+// arithmetic for added insanity.
+func g_ssa() *[7]uint {
+ // Make x a uintptr pointing to where a points.
+ var x uintptr
+ if always {
+ x = uintptr(unsafe.Pointer(a))
+ } else {
+ x = 0
+ }
+ // Clobber the global pointer. The only live ref
+ // to the allocated object is now x.
+ a = nil
+
+ // Offset x by one int.
+ x += unsafe.Sizeof(int(0))
+
+ // Convert to pointer so it should hold
+ // the object live across GC call.
+ p := unsafe.Pointer(x)
+
+ // Call gc.
+ runtime.GC()
+
+ // Convert back to uintptr.
+ y := uintptr(p)
+
+ // Mess with y so that the subsequent cast
+ // to unsafe.Pointer can't be combined with the
+ // uintptr cast above.
+ var z uintptr
+ if always {
+ z = y
+ } else {
+ z = 0
+ }
+ return (*[7]uint)(unsafe.Pointer(z))
+}
+
+func testf(t *testing.T) {
+ a = new([8]uint)
+ for i := 0; i < 8; i++ {
+ a[i] = 0xabcd
+ }
+ c := f_ssa()
+ for i := 0; i < 8; i++ {
+ if c[i] != 0xabcd {
+ t.Fatalf("%d:%x\n", i, c[i])
+ }
+ }
+}
+
+func testg(t *testing.T) {
+ a = new([8]uint)
+ for i := 0; i < 8; i++ {
+ a[i] = 0xabcd
+ }
+ c := g_ssa()
+ for i := 0; i < 7; i++ {
+ if c[i] != 0xabcd {
+ t.Fatalf("%d:%x\n", i, c[i])
+ }
+ }
+}
+
+func alias_ssa(ui64 *uint64, ui32 *uint32) uint32 {
+ *ui32 = 0xffffffff
+ *ui64 = 0 // store
+ ret := *ui32 // load from same address, should be zero
+ *ui64 = 0xffffffffffffffff // store
+ return ret
+}
+func testdse(t *testing.T) {
+ x := int64(-1)
+ // construct two pointers that alias one another
+ ui64 := (*uint64)(unsafe.Pointer(&x))
+ ui32 := (*uint32)(unsafe.Pointer(&x))
+ if want, got := uint32(0), alias_ssa(ui64, ui32); got != want {
+ t.Fatalf("alias_ssa: wanted %d, got %d\n", want, got)
+ }
+}
+
+func TestUnsafe(t *testing.T) {
+ testf(t)
+ testg(t)
+ testdse(t)
+}
diff --git a/src/cmd/compile/internal/gc/testdata/zero_test.go b/src/cmd/compile/internal/gc/testdata/zero_test.go
new file mode 100644
index 0000000..64fa25e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/zero_test.go
@@ -0,0 +1,711 @@
+// Code generated by gen/zeroGen.go. DO NOT EDIT.
+
+package main
+
+import "testing"
+
+type Z1 struct {
+ pre [8]byte
+ mid [1]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero1_ssa(x *[1]byte) {
+ *x = [1]byte{}
+}
+func testZero1(t *testing.T) {
+ a := Z1{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1]byte{255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero1_ssa(&a.mid)
+ want := Z1{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1]byte{0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero1 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z2 struct {
+ pre [8]byte
+ mid [2]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero2_ssa(x *[2]byte) {
+ *x = [2]byte{}
+}
+func testZero2(t *testing.T) {
+ a := Z2{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [2]byte{255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero2_ssa(&a.mid)
+ want := Z2{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [2]byte{0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero2 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z3 struct {
+ pre [8]byte
+ mid [3]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero3_ssa(x *[3]byte) {
+ *x = [3]byte{}
+}
+func testZero3(t *testing.T) {
+ a := Z3{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [3]byte{255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero3_ssa(&a.mid)
+ want := Z3{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [3]byte{0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero3 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z4 struct {
+ pre [8]byte
+ mid [4]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero4_ssa(x *[4]byte) {
+ *x = [4]byte{}
+}
+func testZero4(t *testing.T) {
+ a := Z4{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [4]byte{255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero4_ssa(&a.mid)
+ want := Z4{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [4]byte{0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero4 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z5 struct {
+ pre [8]byte
+ mid [5]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero5_ssa(x *[5]byte) {
+ *x = [5]byte{}
+}
+func testZero5(t *testing.T) {
+ a := Z5{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [5]byte{255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero5_ssa(&a.mid)
+ want := Z5{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [5]byte{0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero5 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z6 struct {
+ pre [8]byte
+ mid [6]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero6_ssa(x *[6]byte) {
+ *x = [6]byte{}
+}
+func testZero6(t *testing.T) {
+ a := Z6{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [6]byte{255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero6_ssa(&a.mid)
+ want := Z6{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [6]byte{0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero6 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z7 struct {
+ pre [8]byte
+ mid [7]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero7_ssa(x *[7]byte) {
+ *x = [7]byte{}
+}
+func testZero7(t *testing.T) {
+ a := Z7{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [7]byte{255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero7_ssa(&a.mid)
+ want := Z7{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [7]byte{0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero7 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z8 struct {
+ pre [8]byte
+ mid [8]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero8_ssa(x *[8]byte) {
+ *x = [8]byte{}
+}
+func testZero8(t *testing.T) {
+ a := Z8{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero8_ssa(&a.mid)
+ want := Z8{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero8 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z9 struct {
+ pre [8]byte
+ mid [9]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero9_ssa(x *[9]byte) {
+ *x = [9]byte{}
+}
+func testZero9(t *testing.T) {
+ a := Z9{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [9]byte{255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero9_ssa(&a.mid)
+ want := Z9{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [9]byte{0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero9 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z10 struct {
+ pre [8]byte
+ mid [10]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero10_ssa(x *[10]byte) {
+ *x = [10]byte{}
+}
+func testZero10(t *testing.T) {
+ a := Z10{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [10]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero10_ssa(&a.mid)
+ want := Z10{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [10]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero10 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z15 struct {
+ pre [8]byte
+ mid [15]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero15_ssa(x *[15]byte) {
+ *x = [15]byte{}
+}
+func testZero15(t *testing.T) {
+ a := Z15{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [15]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero15_ssa(&a.mid)
+ want := Z15{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [15]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero15 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z16 struct {
+ pre [8]byte
+ mid [16]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero16_ssa(x *[16]byte) {
+ *x = [16]byte{}
+}
+func testZero16(t *testing.T) {
+ a := Z16{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero16_ssa(&a.mid)
+ want := Z16{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero16 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z17 struct {
+ pre [8]byte
+ mid [17]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero17_ssa(x *[17]byte) {
+ *x = [17]byte{}
+}
+func testZero17(t *testing.T) {
+ a := Z17{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [17]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero17_ssa(&a.mid)
+ want := Z17{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [17]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero17 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z23 struct {
+ pre [8]byte
+ mid [23]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero23_ssa(x *[23]byte) {
+ *x = [23]byte{}
+}
+func testZero23(t *testing.T) {
+ a := Z23{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [23]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero23_ssa(&a.mid)
+ want := Z23{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [23]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero23 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z24 struct {
+ pre [8]byte
+ mid [24]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero24_ssa(x *[24]byte) {
+ *x = [24]byte{}
+}
+func testZero24(t *testing.T) {
+ a := Z24{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero24_ssa(&a.mid)
+ want := Z24{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero24 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z25 struct {
+ pre [8]byte
+ mid [25]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero25_ssa(x *[25]byte) {
+ *x = [25]byte{}
+}
+func testZero25(t *testing.T) {
+ a := Z25{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [25]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero25_ssa(&a.mid)
+ want := Z25{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [25]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero25 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z31 struct {
+ pre [8]byte
+ mid [31]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero31_ssa(x *[31]byte) {
+ *x = [31]byte{}
+}
+func testZero31(t *testing.T) {
+ a := Z31{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [31]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero31_ssa(&a.mid)
+ want := Z31{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [31]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero31 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z32 struct {
+ pre [8]byte
+ mid [32]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero32_ssa(x *[32]byte) {
+ *x = [32]byte{}
+}
+func testZero32(t *testing.T) {
+ a := Z32{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero32_ssa(&a.mid)
+ want := Z32{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero32 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z33 struct {
+ pre [8]byte
+ mid [33]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero33_ssa(x *[33]byte) {
+ *x = [33]byte{}
+}
+func testZero33(t *testing.T) {
+ a := Z33{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [33]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero33_ssa(&a.mid)
+ want := Z33{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [33]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero33 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z63 struct {
+ pre [8]byte
+ mid [63]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero63_ssa(x *[63]byte) {
+ *x = [63]byte{}
+}
+func testZero63(t *testing.T) {
+ a := Z63{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [63]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero63_ssa(&a.mid)
+ want := Z63{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [63]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero63 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z64 struct {
+ pre [8]byte
+ mid [64]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero64_ssa(x *[64]byte) {
+ *x = [64]byte{}
+}
+func testZero64(t *testing.T) {
+ a := Z64{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero64_ssa(&a.mid)
+ want := Z64{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero64 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z65 struct {
+ pre [8]byte
+ mid [65]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero65_ssa(x *[65]byte) {
+ *x = [65]byte{}
+}
+func testZero65(t *testing.T) {
+ a := Z65{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [65]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero65_ssa(&a.mid)
+ want := Z65{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [65]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero65 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z1023 struct {
+ pre [8]byte
+ mid [1023]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero1023_ssa(x *[1023]byte) {
+ *x = [1023]byte{}
+}
+func testZero1023(t *testing.T) {
+ a := Z1023{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1023]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero1023_ssa(&a.mid)
+ want := Z1023{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1023]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero1023 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z1024 struct {
+ pre [8]byte
+ mid [1024]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero1024_ssa(x *[1024]byte) {
+ *x = [1024]byte{}
+}
+func testZero1024(t *testing.T) {
+ a := Z1024{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1024]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero1024_ssa(&a.mid)
+ want := Z1024{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1024]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero1024 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z1025 struct {
+ pre [8]byte
+ mid [1025]byte
+ post [8]byte
+}
+
+//go:noinline
+func zero1025_ssa(x *[1025]byte) {
+ *x = [1025]byte{}
+}
+func testZero1025(t *testing.T) {
+ a := Z1025{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1025]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero1025_ssa(&a.mid)
+ want := Z1025{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1025]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ if a != want {
+ t.Errorf("zero1025 got=%v, want %v\n", a, want)
+ }
+}
+
+type Z8u1 struct {
+ b bool
+ val [8]byte
+}
+type Z8u2 struct {
+ i uint16
+ val [8]byte
+}
+
+//go:noinline
+func zero8u1_ssa(t *Z8u1) {
+ t.val = [8]byte{}
+}
+
+//go:noinline
+func zero8u2_ssa(t *Z8u2) {
+ t.val = [8]byte{}
+}
+func testZero8u(t *testing.T) {
+ a := Z8u1{false, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero8u1_ssa(&a)
+ want := Z8u1{false, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}}
+ if a != want {
+ t.Errorf("zero8u2 got=%v, want %v\n", a, want)
+ }
+ b := Z8u2{15, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+ zero8u2_ssa(&b)
+ wantb := Z8u2{15, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}}
+ if b != wantb {
+ t.Errorf("zero8u2 got=%v, want %v\n", b, wantb)
+ }
+}
+
+type Z16u1 struct {
+ b bool
+ val [16]byte
+}
+type Z16u2 struct {
+ i uint16
+ val [16]byte
+}
+
+//go:noinline
+func zero16u1_ssa(t *Z16u1) {
+ t.val = [16]byte{}
+}
+
+//go:noinline
+func zero16u2_ssa(t *Z16u2) {
+ t.val = [16]byte{}
+}
+func testZero16u(t *testing.T) {
+ a := Z16u1{false, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero16u1_ssa(&a)
+ want := Z16u1{false, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if a != want {
+ t.Errorf("zero16u2 got=%v, want %v\n", a, want)
+ }
+ b := Z16u2{15, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero16u2_ssa(&b)
+ wantb := Z16u2{15, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if b != wantb {
+ t.Errorf("zero16u2 got=%v, want %v\n", b, wantb)
+ }
+}
+
+type Z24u1 struct {
+ b bool
+ val [24]byte
+}
+type Z24u2 struct {
+ i uint16
+ val [24]byte
+}
+
+//go:noinline
+func zero24u1_ssa(t *Z24u1) {
+ t.val = [24]byte{}
+}
+
+//go:noinline
+func zero24u2_ssa(t *Z24u2) {
+ t.val = [24]byte{}
+}
+func testZero24u(t *testing.T) {
+ a := Z24u1{false, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero24u1_ssa(&a)
+ want := Z24u1{false, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if a != want {
+ t.Errorf("zero24u2 got=%v, want %v\n", a, want)
+ }
+ b := Z24u2{15, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero24u2_ssa(&b)
+ wantb := Z24u2{15, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if b != wantb {
+ t.Errorf("zero24u2 got=%v, want %v\n", b, wantb)
+ }
+}
+
+type Z32u1 struct {
+ b bool
+ val [32]byte
+}
+type Z32u2 struct {
+ i uint16
+ val [32]byte
+}
+
+//go:noinline
+func zero32u1_ssa(t *Z32u1) {
+ t.val = [32]byte{}
+}
+
+//go:noinline
+func zero32u2_ssa(t *Z32u2) {
+ t.val = [32]byte{}
+}
+func testZero32u(t *testing.T) {
+ a := Z32u1{false, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero32u1_ssa(&a)
+ want := Z32u1{false, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if a != want {
+ t.Errorf("zero32u2 got=%v, want %v\n", a, want)
+ }
+ b := Z32u2{15, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero32u2_ssa(&b)
+ wantb := Z32u2{15, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if b != wantb {
+ t.Errorf("zero32u2 got=%v, want %v\n", b, wantb)
+ }
+}
+
+type Z64u1 struct {
+ b bool
+ val [64]byte
+}
+type Z64u2 struct {
+ i uint16
+ val [64]byte
+}
+
+//go:noinline
+func zero64u1_ssa(t *Z64u1) {
+ t.val = [64]byte{}
+}
+
+//go:noinline
+func zero64u2_ssa(t *Z64u2) {
+ t.val = [64]byte{}
+}
+func testZero64u(t *testing.T) {
+ a := Z64u1{false, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero64u1_ssa(&a)
+ want := Z64u1{false, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if a != want {
+ t.Errorf("zero64u2 got=%v, want %v\n", a, want)
+ }
+ b := Z64u2{15, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero64u2_ssa(&b)
+ wantb := Z64u2{15, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if b != wantb {
+ t.Errorf("zero64u2 got=%v, want %v\n", b, wantb)
+ }
+}
+
+type Z256u1 struct {
+ b bool
+ val [256]byte
+}
+type Z256u2 struct {
+ i uint16
+ val [256]byte
+}
+
+//go:noinline
+func zero256u1_ssa(t *Z256u1) {
+ t.val = [256]byte{}
+}
+
+//go:noinline
+func zero256u2_ssa(t *Z256u2) {
+ t.val = [256]byte{}
+}
+func testZero256u(t *testing.T) {
+ a := Z256u1{false, [256]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero256u1_ssa(&a)
+ want := Z256u1{false, [256]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if a != want {
+ t.Errorf("zero256u2 got=%v, want %v\n", a, want)
+ }
+ b := Z256u2{15, [256]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}
+ zero256u2_ssa(&b)
+ wantb := Z256u2{15, [256]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+ if b != wantb {
+ t.Errorf("zero256u2 got=%v, want %v\n", b, wantb)
+ }
+}
+func TestZero(t *testing.T) {
+ testZero1(t)
+ testZero2(t)
+ testZero3(t)
+ testZero4(t)
+ testZero5(t)
+ testZero6(t)
+ testZero7(t)
+ testZero8(t)
+ testZero9(t)
+ testZero10(t)
+ testZero15(t)
+ testZero16(t)
+ testZero17(t)
+ testZero23(t)
+ testZero24(t)
+ testZero25(t)
+ testZero31(t)
+ testZero32(t)
+ testZero33(t)
+ testZero63(t)
+ testZero64(t)
+ testZero65(t)
+ testZero1023(t)
+ testZero1024(t)
+ testZero1025(t)
+ testZero8u(t)
+ testZero16u(t)
+ testZero24u(t)
+ testZero32u(t)
+ testZero64u(t)
+ testZero256u(t)
+}
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/truncconst_test.go b/src/cmd/compile/internal/gc/truncconst_test.go
new file mode 100644
index 0000000..d153818
--- /dev/null
+++ b/src/cmd/compile/internal/gc/truncconst_test.go
@@ -0,0 +1,63 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import "testing"
+
+var f52want float64 = 1.0 / (1 << 52)
+var f53want float64 = 1.0 / (1 << 53)
+
+func TestTruncFlt(t *testing.T) {
+ const f52 = 1 + 1.0/(1<<52)
+ const f53 = 1 + 1.0/(1<<53)
+
+ if got := f52 - 1; got != f52want {
+ t.Errorf("f52-1 = %g, want %g", got, f52want)
+ }
+ if got := float64(f52) - 1; got != f52want {
+ t.Errorf("float64(f52)-1 = %g, want %g", got, f52want)
+ }
+ if got := f53 - 1; got != f53want {
+ t.Errorf("f53-1 = %g, want %g", got, f53want)
+ }
+ if got := float64(f53) - 1; got != 0 {
+ t.Errorf("float64(f53)-1 = %g, want 0", got)
+ }
+}
+
+func TestTruncCmplx(t *testing.T) {
+ const r52 = complex(1+1.0/(1<<52), 0)
+ const r53 = complex(1+1.0/(1<<53), 0)
+
+ if got := real(r52 - 1); got != f52want {
+ t.Errorf("real(r52-1) = %g, want %g", got, f52want)
+ }
+ if got := real(complex128(r52) - 1); got != f52want {
+ t.Errorf("real(complex128(r52)-1) = %g, want %g", got, f52want)
+ }
+ if got := real(r53 - 1); got != f53want {
+ t.Errorf("real(r53-1) = %g, want %g", got, f53want)
+ }
+ if got := real(complex128(r53) - 1); got != 0 {
+ t.Errorf("real(complex128(r53)-1) = %g, want 0", got)
+ }
+
+ const i52 = complex(0, 1+1.0/(1<<52))
+ const i53 = complex(0, 1+1.0/(1<<53))
+
+ if got := imag(i52 - 1i); got != f52want {
+ t.Errorf("imag(i52-1i) = %g, want %g", got, f52want)
+ }
+ if got := imag(complex128(i52) - 1i); got != f52want {
+ t.Errorf("imag(complex128(i52)-1i) = %g, want %g", got, f52want)
+ }
+ if got := imag(i53 - 1i); got != f53want {
+ t.Errorf("imag(i53-1i) = %g, want %g", got, f53want)
+ }
+ if got := imag(complex128(i53) - 1i); got != 0 {
+ t.Errorf("imag(complex128(i53)-1i) = %g, want 0", got)
+ }
+
+}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
new file mode 100644
index 0000000..c0b0503
--- /dev/null
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -0,0 +1,4019 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "fmt"
+ "strings"
+)
+
+// To enable tracing support (-t flag), set enableTrace to true.
+const enableTrace = false
+
+var trace bool
+var traceIndent []byte
+var skipDowidthForTracing bool
+
+func tracePrint(title string, n *Node) func(np **Node) {
+ indent := traceIndent
+
+ // guard against nil
+ var pos, op string
+ var tc uint8
+ if n != nil {
+ pos = linestr(n.Pos)
+ op = n.Op.String()
+ tc = n.Typecheck()
+ }
+
+ skipDowidthForTracing = true
+ defer func() { skipDowidthForTracing = false }()
+ fmt.Printf("%s: %s%s %p %s %v tc=%d\n", pos, indent, title, n, op, n, tc)
+ traceIndent = append(traceIndent, ". "...)
+
+ return func(np **Node) {
+ traceIndent = traceIndent[:len(traceIndent)-2]
+
+ // if we have a result, use that
+ if np != nil {
+ n = *np
+ }
+
+ // guard against nil
+ // use outer pos, op so we don't get empty pos/op if n == nil (nicer output)
+ var tc uint8
+ var typ *types.Type
+ if n != nil {
+ pos = linestr(n.Pos)
+ op = n.Op.String()
+ tc = n.Typecheck()
+ typ = n.Type
+ }
+
+ skipDowidthForTracing = true
+ defer func() { skipDowidthForTracing = false }()
+ fmt.Printf("%s: %s=> %p %s %v tc=%d type=%#L\n", pos, indent, n, op, n, tc, typ)
+ }
+}
+
+const (
+ ctxStmt = 1 << iota // evaluated at statement level
+ ctxExpr // evaluated in value context
+ ctxType // evaluated in type context
+ ctxCallee // call-only expressions are ok
+ ctxMultiOK // multivalue function returns are ok
+ ctxAssign // assigning to expression
+)
+
+// type checks the whole tree of an expression.
+// calculates expression types.
+// evaluates compile time constants.
+// marks variables that escape the local frame.
+// rewrites n.Op to be more specific in some cases.
+
+var typecheckdefstack []*Node
+
+// resolve ONONAME to definition, if any.
+func resolve(n *Node) (res *Node) {
+ if n == nil || n.Op != ONONAME {
+ return n
+ }
+
+ // only trace if there's work to do
+ if enableTrace && trace {
+ defer tracePrint("resolve", n)(&res)
+ }
+
+ if n.Sym.Pkg != localpkg {
+ if inimport {
+ Fatalf("recursive inimport")
+ }
+ inimport = true
+ expandDecl(n)
+ inimport = false
+ return n
+ }
+
+ r := asNode(n.Sym.Def)
+ if r == nil {
+ return n
+ }
+
+ if r.Op == OIOTA {
+ if x := getIotaValue(); x >= 0 {
+ return nodintconst(x)
+ }
+ return n
+ }
+
+ return r
+}
+
+func typecheckslice(l []*Node, top int) {
+ for i := range l {
+ l[i] = typecheck(l[i], top)
+ }
+}
+
+var _typekind = []string{
+ TINT: "int",
+ TUINT: "uint",
+ TINT8: "int8",
+ TUINT8: "uint8",
+ TINT16: "int16",
+ TUINT16: "uint16",
+ TINT32: "int32",
+ TUINT32: "uint32",
+ TINT64: "int64",
+ TUINT64: "uint64",
+ TUINTPTR: "uintptr",
+ TCOMPLEX64: "complex64",
+ TCOMPLEX128: "complex128",
+ TFLOAT32: "float32",
+ TFLOAT64: "float64",
+ TBOOL: "bool",
+ TSTRING: "string",
+ TPTR: "pointer",
+ TUNSAFEPTR: "unsafe.Pointer",
+ TSTRUCT: "struct",
+ TINTER: "interface",
+ TCHAN: "chan",
+ TMAP: "map",
+ TARRAY: "array",
+ TSLICE: "slice",
+ TFUNC: "func",
+ TNIL: "nil",
+ TIDEAL: "untyped number",
+}
+
+func typekind(t *types.Type) string {
+ if t.IsUntyped() {
+ return fmt.Sprintf("%v", t)
+ }
+ et := t.Etype
+ if int(et) < len(_typekind) {
+ s := _typekind[et]
+ if s != "" {
+ return s
+ }
+ }
+ return fmt.Sprintf("etype=%d", et)
+}
+
+func cycleFor(start *Node) []*Node {
+ // Find the start node in typecheck_tcstack.
+ // We know that it must exist because each time we mark
+ // a node with n.SetTypecheck(2) we push it on the stack,
+ // and each time we mark a node with n.SetTypecheck(2) we
+ // pop it from the stack. We hit a cycle when we encounter
+ // a node marked 2 in which case is must be on the stack.
+ i := len(typecheck_tcstack) - 1
+ for i > 0 && typecheck_tcstack[i] != start {
+ i--
+ }
+
+ // collect all nodes with same Op
+ var cycle []*Node
+ for _, n := range typecheck_tcstack[i:] {
+ if n.Op == start.Op {
+ cycle = append(cycle, n)
+ }
+ }
+
+ return cycle
+}
+
+func cycleTrace(cycle []*Node) string {
+ var s string
+ for i, n := range cycle {
+ s += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cycle[(i+1)%len(cycle)])
+ }
+ return s
+}
+
+var typecheck_tcstack []*Node
+
+// typecheck type checks node n.
+// The result of typecheck MUST be assigned back to n, e.g.
+// n.Left = typecheck(n.Left, top)
+func typecheck(n *Node, top int) (res *Node) {
+ // cannot type check until all the source has been parsed
+ if !typecheckok {
+ Fatalf("early typecheck")
+ }
+
+ if n == nil {
+ return nil
+ }
+
+ // only trace if there's work to do
+ if enableTrace && trace {
+ defer tracePrint("typecheck", n)(&res)
+ }
+
+ lno := setlineno(n)
+
+ // Skip over parens.
+ for n.Op == OPAREN {
+ n = n.Left
+ }
+
+ // Resolve definition of name and value of iota lazily.
+ n = resolve(n)
+
+ // Skip typecheck if already done.
+ // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
+ if n.Typecheck() == 1 {
+ switch n.Op {
+ case ONAME, OTYPE, OLITERAL, OPACK:
+ break
+
+ default:
+ lineno = lno
+ return n
+ }
+ }
+
+ if n.Typecheck() == 2 {
+ // Typechecking loop. Trying printing a meaningful message,
+ // otherwise a stack trace of typechecking.
+ switch n.Op {
+ // We can already diagnose variables used as types.
+ case ONAME:
+ if top&(ctxExpr|ctxType) == ctxType {
+ yyerror("%v is not a type", n)
+ }
+
+ case OTYPE:
+ // Only report a type cycle if we are expecting a type.
+ // Otherwise let other code report an error.
+ if top&ctxType == ctxType {
+ // A cycle containing only alias types is an error
+ // since it would expand indefinitely when aliases
+ // are substituted.
+ cycle := cycleFor(n)
+ for _, n1 := range cycle {
+ if n1.Name != nil && !n1.Name.Param.Alias() {
+ // Cycle is ok. But if n is an alias type and doesn't
+ // have a type yet, we have a recursive type declaration
+ // with aliases that we can't handle properly yet.
+ // Report an error rather than crashing later.
+ if n.Name != nil && n.Name.Param.Alias() && n.Type == nil {
+ lineno = n.Pos
+ Fatalf("cannot handle alias type declaration (issue #25838): %v", n)
+ }
+ lineno = lno
+ return n
+ }
+ }
+ yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, cycleTrace(cycle))
+ }
+
+ case OLITERAL:
+ if top&(ctxExpr|ctxType) == ctxType {
+ yyerror("%v is not a type", n)
+ break
+ }
+ yyerrorl(n.Pos, "constant definition loop%s", cycleTrace(cycleFor(n)))
+ }
+
+ if nsavederrors+nerrors == 0 {
+ var trace string
+ for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
+ x := typecheck_tcstack[i]
+ trace += fmt.Sprintf("\n\t%v %v", x.Line(), x)
+ }
+ yyerror("typechecking loop involving %v%s", n, trace)
+ }
+
+ lineno = lno
+ return n
+ }
+
+ n.SetTypecheck(2)
+
+ typecheck_tcstack = append(typecheck_tcstack, n)
+ n = typecheck1(n, top)
+
+ n.SetTypecheck(1)
+
+ last := len(typecheck_tcstack) - 1
+ typecheck_tcstack[last] = nil
+ typecheck_tcstack = typecheck_tcstack[:last]
+
+ lineno = lno
+ return n
+}
+
+// indexlit implements typechecking of untyped values as
+// array/slice indexes. It is almost equivalent to defaultlit
+// but also accepts untyped numeric values representable as
+// value of type int (see also checkmake for comparison).
+// The result of indexlit MUST be assigned back to n, e.g.
+// n.Left = indexlit(n.Left)
+func indexlit(n *Node) *Node {
+ if n != nil && n.Type != nil && n.Type.Etype == TIDEAL {
+ return defaultlit(n, types.Types[TINT])
+ }
+ return n
+}
+
+// The result of typecheck1 MUST be assigned back to n, e.g.
+// n.Left = typecheck1(n.Left, top)
+func typecheck1(n *Node, top int) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheck1", n)(&res)
+ }
+
+ switch n.Op {
+ case OLITERAL, ONAME, ONONAME, OTYPE:
+ if n.Sym == nil {
+ break
+ }
+
+ if n.Op == ONAME && n.SubOp() != 0 && top&ctxCallee == 0 {
+ yyerror("use of builtin %v not in function call", n.Sym)
+ n.Type = nil
+ return n
+ }
+
+ typecheckdef(n)
+ if n.Op == ONONAME {
+ n.Type = nil
+ return n
+ }
+ }
+
+ ok := 0
+ switch n.Op {
+ // until typecheck is complete, do nothing.
+ default:
+ Dump("typecheck", n)
+
+ Fatalf("typecheck %v", n.Op)
+
+ // names
+ case OLITERAL:
+ ok |= ctxExpr
+
+ if n.Type == nil && n.Val().Ctype() == CTSTR {
+ n.Type = types.UntypedString
+ }
+
+ case ONONAME:
+ ok |= ctxExpr
+
+ case ONAME:
+ if n.Name.Decldepth == 0 {
+ n.Name.Decldepth = decldepth
+ }
+ if n.SubOp() != 0 {
+ ok |= ctxCallee
+ break
+ }
+
+ if top&ctxAssign == 0 {
+ // not a write to the variable
+ if n.isBlank() {
+ yyerror("cannot use _ as value")
+ n.Type = nil
+ return n
+ }
+
+ n.Name.SetUsed(true)
+ }
+
+ ok |= ctxExpr
+
+ case OPACK:
+ yyerror("use of package %v without selector", n.Sym)
+ n.Type = nil
+ return n
+
+ case ODDD:
+ break
+
+ // types (ODEREF is with exprs)
+ case OTYPE:
+ ok |= ctxType
+
+ if n.Type == nil {
+ return n
+ }
+
+ case OTARRAY:
+ ok |= ctxType
+ r := typecheck(n.Right, ctxType)
+ if r.Type == nil {
+ n.Type = nil
+ return n
+ }
+
+ var t *types.Type
+ if n.Left == nil {
+ t = types.NewSlice(r.Type)
+ } else if n.Left.Op == ODDD {
+ if !n.Diag() {
+ n.SetDiag(true)
+ yyerror("use of [...] array outside of array literal")
+ }
+ n.Type = nil
+ return n
+ } else {
+ n.Left = indexlit(typecheck(n.Left, ctxExpr))
+ l := n.Left
+ if consttype(l) != CTINT {
+ switch {
+ case l.Type == nil:
+ // Error already reported elsewhere.
+ case l.Type.IsInteger() && l.Op != OLITERAL:
+ yyerror("non-constant array bound %v", l)
+ default:
+ yyerror("invalid array bound %v", l)
+ }
+ n.Type = nil
+ return n
+ }
+
+ v := l.Val()
+ if doesoverflow(v, types.Types[TINT]) {
+ 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")
+ n.Type = nil
+ return n
+ }
+ t = types.NewArray(r.Type, bound)
+ }
+
+ setTypeNode(n, t)
+ n.Left = nil
+ n.Right = nil
+ checkwidth(t)
+
+ case OTMAP:
+ ok |= ctxType
+ n.Left = typecheck(n.Left, ctxType)
+ n.Right = typecheck(n.Right, ctxType)
+ l := n.Left
+ r := n.Right
+ if l.Type == nil || r.Type == nil {
+ n.Type = nil
+ return n
+ }
+ if l.Type.NotInHeap() {
+ yyerror("incomplete (or unallocatable) map key not allowed")
+ }
+ if r.Type.NotInHeap() {
+ yyerror("incomplete (or unallocatable) map value not allowed")
+ }
+
+ setTypeNode(n, types.NewMap(l.Type, r.Type))
+ mapqueue = append(mapqueue, n) // check map keys when all types are settled
+ n.Left = nil
+ n.Right = nil
+
+ case OTCHAN:
+ ok |= ctxType
+ n.Left = typecheck(n.Left, ctxType)
+ l := n.Left
+ if l.Type == nil {
+ n.Type = nil
+ return n
+ }
+ if l.Type.NotInHeap() {
+ yyerror("chan of incomplete (or unallocatable) type not allowed")
+ }
+
+ setTypeNode(n, types.NewChan(l.Type, n.TChanDir()))
+ n.Left = nil
+ n.ResetAux()
+
+ case OTSTRUCT:
+ ok |= ctxType
+ setTypeNode(n, tostruct(n.List.Slice()))
+ n.List.Set(nil)
+
+ case OTINTER:
+ ok |= ctxType
+ setTypeNode(n, tointerface(n.List.Slice()))
+
+ case OTFUNC:
+ ok |= ctxType
+ setTypeNode(n, functype(n.Left, n.List.Slice(), n.Rlist.Slice()))
+ n.Left = nil
+ n.List.Set(nil)
+ n.Rlist.Set(nil)
+
+ // type or expr
+ case ODEREF:
+ n.Left = typecheck(n.Left, ctxExpr|ctxType)
+ l := n.Left
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if l.Op == OTYPE {
+ ok |= ctxType
+ setTypeNode(n, types.NewPtr(l.Type))
+ n.Left = nil
+ // Ensure l.Type gets dowidth'd for the backend. Issue 20174.
+ checkwidth(l.Type)
+ break
+ }
+
+ if !t.IsPtr() {
+ if top&(ctxExpr|ctxStmt) != 0 {
+ yyerror("invalid indirect of %L", n.Left)
+ n.Type = nil
+ return n
+ }
+
+ break
+ }
+
+ ok |= ctxExpr
+ n.Type = t.Elem()
+
+ // arithmetic exprs
+ case OASOP,
+ OADD,
+ OAND,
+ OANDAND,
+ OANDNOT,
+ ODIV,
+ OEQ,
+ OGE,
+ OGT,
+ OLE,
+ OLT,
+ OLSH,
+ ORSH,
+ OMOD,
+ OMUL,
+ ONE,
+ OOR,
+ OOROR,
+ OSUB,
+ OXOR:
+ var l *Node
+ var op Op
+ var r *Node
+ if n.Op == OASOP {
+ ok |= ctxStmt
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Right = typecheck(n.Right, ctxExpr)
+ l = n.Left
+ r = n.Right
+ checkassign(n, n.Left)
+ if l.Type == nil || r.Type == nil {
+ n.Type = nil
+ return n
+ }
+ if n.Implicit() && !okforarith[l.Type.Etype] {
+ yyerror("invalid operation: %v (non-numeric type %v)", n, l.Type)
+ n.Type = nil
+ return n
+ }
+ // TODO(marvin): Fix Node.EType type union.
+ op = n.SubOp()
+ } else {
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Right = typecheck(n.Right, ctxExpr)
+ l = n.Left
+ r = n.Right
+ if l.Type == nil || r.Type == nil {
+ n.Type = nil
+ return n
+ }
+ op = n.Op
+ }
+ if op == OLSH || op == ORSH {
+ r = defaultlit(r, types.Types[TUINT])
+ n.Right = r
+ t := r.Type
+ if !t.IsInteger() {
+ yyerror("invalid operation: %v (shift count type %v, must be integer)", n, r.Type)
+ n.Type = nil
+ return n
+ }
+ if t.IsSigned() && !langSupported(1, 13, curpkg()) {
+ yyerrorv("go1.13", "invalid operation: %v (signed shift count type %v)", 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)
+ n.Type = nil
+ return n
+ }
+
+ // no defaultlit for left
+ // the outer context gives the type
+ n.Type = l.Type
+ if (l.Type == types.UntypedFloat || l.Type == types.UntypedComplex) && r.Op == OLITERAL {
+ n.Type = types.UntypedInt
+ }
+
+ break
+ }
+
+ // For "x == x && len(s)", it's better to report that "len(s)" (type int)
+ // can't be used with "&&" than to report that "x == x" (type untyped bool)
+ // can't be converted to int (see issue #41500).
+ if n.Op == OANDAND || n.Op == OOROR {
+ if !n.Left.Type.IsBoolean() {
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(n.Left.Type))
+ n.Type = nil
+ return n
+ }
+ if !n.Right.Type.IsBoolean() {
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(n.Right.Type))
+ n.Type = nil
+ return n
+ }
+ }
+
+ // ideal mixed with non-ideal
+ l, r = defaultlit2(l, r, false)
+
+ n.Left = l
+ n.Right = r
+ if l.Type == nil || r.Type == nil {
+ n.Type = nil
+ return n
+ }
+ t := l.Type
+ if t.Etype == TIDEAL {
+ t = r.Type
+ }
+ et := t.Etype
+ if et == TIDEAL {
+ et = TINT
+ }
+ aop := OXXX
+ if iscmp[n.Op] && t.Etype != TIDEAL && !types.Identical(l.Type, r.Type) {
+ // comparison is okay as long as one side is
+ // assignable to the other. convert so they have
+ // the same type.
+ //
+ // the only conversion that isn't a no-op is concrete == interface.
+ // in that case, check comparability of the concrete type.
+ // The conversion allocates, so only do it if the concrete type is huge.
+ converted := false
+ if r.Type.Etype != TBLANK {
+ aop, _ = assignop(l.Type, r.Type)
+ if aop != OXXX {
+ if r.Type.IsInterface() && !l.Type.IsInterface() && !IsComparable(l.Type) {
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
+ n.Type = nil
+ return n
+ }
+
+ dowidth(l.Type)
+ if r.Type.IsInterface() == l.Type.IsInterface() || l.Type.Width >= 1<<16 {
+ l = nod(aop, l, nil)
+ l.Type = r.Type
+ l.SetTypecheck(1)
+ n.Left = l
+ }
+
+ t = r.Type
+ converted = true
+ }
+ }
+
+ if !converted && l.Type.Etype != TBLANK {
+ aop, _ = assignop(r.Type, l.Type)
+ if aop != OXXX {
+ if l.Type.IsInterface() && !r.Type.IsInterface() && !IsComparable(r.Type) {
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
+ n.Type = nil
+ return n
+ }
+
+ dowidth(r.Type)
+ if r.Type.IsInterface() == l.Type.IsInterface() || r.Type.Width >= 1<<16 {
+ r = nod(aop, r, nil)
+ r.Type = l.Type
+ r.SetTypecheck(1)
+ n.Right = r
+ }
+
+ t = l.Type
+ }
+ }
+
+ et = t.Etype
+ }
+
+ if t.Etype != TIDEAL && !types.Identical(l.Type, r.Type) {
+ l, r = defaultlit2(l, r, true)
+ if l.Type == nil || r.Type == nil {
+ n.Type = nil
+ return n
+ }
+ if l.Type.IsInterface() == r.Type.IsInterface() || aop == 0 {
+ yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
+ n.Type = nil
+ return n
+ }
+ }
+
+ if t.Etype == TIDEAL {
+ t = mixUntyped(l.Type, r.Type)
+ }
+ if dt := defaultType(t); !okfor[op][dt.Etype] {
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
+ n.Type = nil
+ return n
+ }
+
+ // okfor allows any array == array, map == map, func == func.
+ // restrict to slice/map/func == nil and nil == slice/map/func.
+ if l.Type.IsArray() && !IsComparable(l.Type) {
+ yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type)
+ n.Type = nil
+ return n
+ }
+
+ if l.Type.IsSlice() && !l.isNil() && !r.isNil() {
+ yyerror("invalid operation: %v (slice can only be compared to nil)", n)
+ n.Type = nil
+ return n
+ }
+
+ if l.Type.IsMap() && !l.isNil() && !r.isNil() {
+ yyerror("invalid operation: %v (map can only be compared to nil)", n)
+ n.Type = nil
+ return n
+ }
+
+ if l.Type.Etype == TFUNC && !l.isNil() && !r.isNil() {
+ yyerror("invalid operation: %v (func can only be compared to nil)", n)
+ n.Type = nil
+ return n
+ }
+
+ if l.Type.IsStruct() {
+ if f := IncomparableField(l.Type); f != nil {
+ yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
+ n.Type = nil
+ return n
+ }
+ }
+
+ if iscmp[n.Op] {
+ evconst(n)
+ t = types.UntypedBool
+ if n.Op != OLITERAL {
+ l, r = defaultlit2(l, r, true)
+ n.Left = l
+ n.Right = r
+ }
+ }
+
+ if et == TSTRING && n.Op == OADD {
+ // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
+ n.Op = OADDSTR
+
+ if l.Op == OADDSTR {
+ n.List.Set(l.List.Slice())
+ } else {
+ n.List.Set1(l)
+ }
+ if r.Op == OADDSTR {
+ n.List.AppendNodes(&r.List)
+ } else {
+ n.List.Append(r)
+ }
+ n.Left = nil
+ n.Right = nil
+ }
+
+ if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
+ if r.Val().U.(*Mpint).CmpInt64(0) == 0 {
+ yyerror("division by zero")
+ n.Type = nil
+ return n
+ }
+ }
+
+ n.Type = t
+
+ case OBITNOT, ONEG, ONOT, OPLUS:
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ l := n.Left
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if !okfor[n.Op][defaultType(t).Etype] {
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(t))
+ n.Type = nil
+ return n
+ }
+
+ n.Type = t
+
+ // exprs
+ case OADDR:
+ ok |= ctxExpr
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ if n.Left.Type == nil {
+ n.Type = nil
+ return n
+ }
+
+ switch n.Left.Op {
+ case OARRAYLIT, OMAPLIT, OSLICELIT, OSTRUCTLIT:
+ n.Op = OPTRLIT
+
+ default:
+ checklvalue(n.Left, "take the address of")
+ r := outervalue(n.Left)
+ if r.Op == ONAME {
+ if r.Orig != r {
+ Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
+ }
+ r.Name.SetAddrtaken(true)
+ if r.Name.IsClosureVar() && !capturevarscomplete {
+ // Mark the original variable as Addrtaken so that capturevars
+ // knows not to pass it by value.
+ // But if the capturevars phase is complete, don't touch it,
+ // in case l.Name's containing function has not yet been compiled.
+ r.Name.Defn.Name.SetAddrtaken(true)
+ }
+ }
+ n.Left = defaultlit(n.Left, nil)
+ if n.Left.Type == nil {
+ n.Type = nil
+ return n
+ }
+ }
+
+ n.Type = types.NewPtr(n.Left.Type)
+
+ case OCOMPLIT:
+ ok |= ctxExpr
+ n = typecheckcomplit(n)
+ if n.Type == nil {
+ return n
+ }
+
+ case OXDOT, ODOT:
+ if n.Op == OXDOT {
+ n = adddot(n)
+ n.Op = ODOT
+ if n.Left == nil {
+ n.Type = nil
+ return n
+ }
+ }
+
+ n.Left = typecheck(n.Left, ctxExpr|ctxType)
+
+ n.Left = defaultlit(n.Left, nil)
+
+ t := n.Left.Type
+ if t == nil {
+ adderrorname(n)
+ n.Type = nil
+ return n
+ }
+
+ s := n.Sym
+
+ if n.Left.Op == OTYPE {
+ n = typecheckMethodExpr(n)
+ if n.Type == nil {
+ return n
+ }
+ ok = ctxExpr
+ break
+ }
+
+ if t.IsPtr() && !t.Elem().IsInterface() {
+ t = t.Elem()
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ n.Op = ODOTPTR
+ checkwidth(t)
+ }
+
+ if n.Sym.IsBlank() {
+ yyerror("cannot refer to blank field or method")
+ n.Type = nil
+ return n
+ }
+
+ if lookdot(n, t, 0) == nil {
+ // 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)
+
+ case t.IsPtr() && t.Elem().IsInterface():
+ // Pointer to interface is almost always a mistake.
+ yyerror("%v undefined (type %v is pointer to interface, not interface)", n, n.Left.Type)
+
+ case lookdot(n, t, 1) != nil:
+ // Field or method matches by name, but it is not exported.
+ yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym)
+
+ default:
+ if mt := lookdot(n, t, 2); mt != nil && visible(mt.Sym) { // 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)
+ } else {
+ yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym)
+ }
+ }
+ n.Type = nil
+ return n
+ }
+
+ switch n.Op {
+ case ODOTINTER, ODOTMETH:
+ if top&ctxCallee != 0 {
+ ok |= ctxCallee
+ } else {
+ typecheckpartialcall(n, s)
+ ok |= ctxExpr
+ }
+
+ default:
+ ok |= ctxExpr
+ }
+
+ case ODOTTYPE:
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ l := n.Left
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if !t.IsInterface() {
+ yyerror("invalid type assertion: %v (non-interface type %v on left)", n, t)
+ n.Type = nil
+ return n
+ }
+
+ if n.Right != nil {
+ n.Right = typecheck(n.Right, ctxType)
+ n.Type = n.Right.Type
+ n.Right = nil
+ if n.Type == nil {
+ return n
+ }
+ }
+
+ if n.Type != nil && !n.Type.IsInterface() {
+ var missing, have *types.Field
+ var ptr int
+ if !implements(n.Type, t, &missing, &have, &ptr) {
+ if have != nil && have.Sym == missing.Sym {
+ yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+
+ "\t\thave %v%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)
+ } else if have != nil {
+ 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)
+ }
+ n.Type = nil
+ return n
+ }
+ }
+
+ case OINDEX:
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ n.Left = implicitstar(n.Left)
+ l := n.Left
+ n.Right = typecheck(n.Right, ctxExpr)
+ r := n.Right
+ t := l.Type
+ if t == nil || r.Type == nil {
+ n.Type = nil
+ return n
+ }
+ switch t.Etype {
+ default:
+ yyerror("invalid operation: %v (type %v does not support indexing)", n, t)
+ n.Type = nil
+ return n
+
+ case TSTRING, TARRAY, TSLICE:
+ n.Right = indexlit(n.Right)
+ if t.IsString() {
+ n.Type = types.Bytetype
+ } else {
+ n.Type = t.Elem()
+ }
+ why := "string"
+ if t.IsArray() {
+ why = "array"
+ } else if t.IsSlice() {
+ why = "slice"
+ }
+
+ if n.Right.Type != nil && !n.Right.Type.IsInteger() {
+ yyerror("non-integer %s index %v", why, n.Right)
+ break
+ }
+
+ if !n.Bounded() && Isconst(n.Right, CTINT) {
+ x := n.Right.Int64Val()
+ if x < 0 {
+ 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())
+ } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.StringVal())) {
+ yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.StringVal()))
+ } else if n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ yyerror("invalid %s index %v (index too large)", why, n.Right)
+ }
+ }
+
+ case TMAP:
+ n.Right = assignconv(n.Right, t.Key(), "map index")
+ n.Type = t.Elem()
+ n.Op = OINDEXMAP
+ n.ResetAux()
+ }
+
+ case ORECV:
+ ok |= ctxStmt | ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ l := n.Left
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if !t.IsChan() {
+ 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)
+ n.Type = nil
+ return n
+ }
+
+ n.Type = t.Elem()
+
+ case OSEND:
+ ok |= ctxStmt
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Right = typecheck(n.Right, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ t := n.Left.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if !t.IsChan() {
+ 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)
+ n.Type = nil
+ return n
+ }
+
+ n.Right = assignconv(n.Right, t.Elem(), "send")
+ if n.Right.Type == nil {
+ n.Type = nil
+ return n
+ }
+ n.Type = nil
+
+ case OSLICEHEADER:
+ // Errors here are Fatalf instead of yyerror because only the compiler
+ // can construct an OSLICEHEADER node.
+ // Components used in OSLICEHEADER that are supplied by parsed source code
+ // have already been typechecked in e.g. OMAKESLICE earlier.
+ ok |= ctxExpr
+
+ t := n.Type
+ if t == nil {
+ Fatalf("no type specified for OSLICEHEADER")
+ }
+
+ if !t.IsSlice() {
+ Fatalf("invalid type %v for OSLICEHEADER", n.Type)
+ }
+
+ if n.Left == nil || n.Left.Type == nil || !n.Left.Type.IsUnsafePtr() {
+ Fatalf("need unsafe.Pointer for OSLICEHEADER")
+ }
+
+ if x := n.List.Len(); x != 2 {
+ Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x)
+ }
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ l := typecheck(n.List.First(), ctxExpr)
+ c := typecheck(n.List.Second(), ctxExpr)
+ l = defaultlit(l, types.Types[TINT])
+ c = defaultlit(c, types.Types[TINT])
+
+ if Isconst(l, CTINT) && l.Int64Val() < 0 {
+ Fatalf("len for OSLICEHEADER must be non-negative")
+ }
+
+ if Isconst(c, CTINT) && c.Int64Val() < 0 {
+ Fatalf("cap for OSLICEHEADER must be non-negative")
+ }
+
+ if Isconst(l, CTINT) && Isconst(c, CTINT) && l.Val().U.(*Mpint).Cmp(c.Val().U.(*Mpint)) > 0 {
+ Fatalf("len larger than cap for OSLICEHEADER")
+ }
+
+ n.List.SetFirst(l)
+ n.List.SetSecond(c)
+
+ case OMAKESLICECOPY:
+ // Errors here are Fatalf instead of yyerror because only the compiler
+ // can construct an OMAKESLICECOPY node.
+ // Components used in OMAKESCLICECOPY that are supplied by parsed source code
+ // have already been typechecked in OMAKE and OCOPY earlier.
+ ok |= ctxExpr
+
+ t := n.Type
+
+ if t == nil {
+ Fatalf("no type specified for OMAKESLICECOPY")
+ }
+
+ if !t.IsSlice() {
+ Fatalf("invalid type %v for OMAKESLICECOPY", n.Type)
+ }
+
+ if n.Left == nil {
+ Fatalf("missing len argument for OMAKESLICECOPY")
+ }
+
+ if n.Right == nil {
+ Fatalf("missing slice argument to copy for OMAKESLICECOPY")
+ }
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Right = typecheck(n.Right, ctxExpr)
+
+ n.Left = defaultlit(n.Left, types.Types[TINT])
+
+ if !n.Left.Type.IsInteger() && n.Type.Etype != TIDEAL {
+ yyerror("non-integer len argument in OMAKESLICECOPY")
+ }
+
+ if Isconst(n.Left, CTINT) {
+ if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ Fatalf("len for OMAKESLICECOPY too large")
+ }
+ if n.Left.Int64Val() < 0 {
+ Fatalf("len for OMAKESLICECOPY must be non-negative")
+ }
+ }
+
+ case OSLICE, OSLICE3:
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ low, high, max := n.SliceBounds()
+ hasmax := n.Op.IsSlice3()
+ low = typecheck(low, ctxExpr)
+ high = typecheck(high, ctxExpr)
+ max = typecheck(max, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ low = indexlit(low)
+ high = indexlit(high)
+ max = indexlit(max)
+ n.SetSliceBounds(low, high, max)
+ l := n.Left
+ if l.Type == nil {
+ n.Type = nil
+ return n
+ }
+ if l.Type.IsArray() {
+ if !islvalue(n.Left) {
+ yyerror("invalid operation %v (slice of unaddressable value)", n)
+ n.Type = nil
+ return n
+ }
+
+ n.Left = nod(OADDR, n.Left, nil)
+ n.Left.SetImplicit(true)
+ n.Left = typecheck(n.Left, ctxExpr)
+ l = n.Left
+ }
+ t := l.Type
+ var tp *types.Type
+ if t.IsString() {
+ if hasmax {
+ yyerror("invalid operation %v (3-index slice of string)", n)
+ n.Type = nil
+ return n
+ }
+ n.Type = t
+ n.Op = OSLICESTR
+ } else if t.IsPtr() && t.Elem().IsArray() {
+ tp = t.Elem()
+ n.Type = types.NewSlice(tp.Elem())
+ dowidth(n.Type)
+ if hasmax {
+ n.Op = OSLICE3ARR
+ } else {
+ n.Op = OSLICEARR
+ }
+ } else if t.IsSlice() {
+ n.Type = t
+ } else {
+ yyerror("cannot slice %v (type %v)", l, t)
+ n.Type = nil
+ return n
+ }
+
+ if low != nil && !checksliceindex(l, low, tp) {
+ n.Type = nil
+ return n
+ }
+ if high != nil && !checksliceindex(l, high, tp) {
+ n.Type = nil
+ return n
+ }
+ if max != nil && !checksliceindex(l, max, tp) {
+ n.Type = nil
+ return n
+ }
+ if !checksliceconst(low, high) || !checksliceconst(low, max) || !checksliceconst(high, max) {
+ n.Type = nil
+ return n
+ }
+
+ // call and call like
+ case OCALL:
+ typecheckslice(n.Ninit.Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907)
+ n.Left = typecheck(n.Left, ctxExpr|ctxType|ctxCallee)
+ if n.Left.Diag() {
+ n.SetDiag(true)
+ }
+
+ l := n.Left
+
+ if l.Op == ONAME && l.SubOp() != 0 {
+ if n.IsDDD() && l.SubOp() != OAPPEND {
+ yyerror("invalid use of ... with builtin %v", l)
+ }
+
+ // builtin: OLEN, OCAP, etc.
+ n.Op = l.SubOp()
+ n.Left = n.Right
+ n.Right = nil
+ n = typecheck1(n, top)
+ return n
+ }
+
+ n.Left = defaultlit(n.Left, nil)
+ l = n.Left
+ if l.Op == OTYPE {
+ if n.IsDDD() {
+ if !l.Type.Broke() {
+ yyerror("invalid use of ... in type conversion to %v", l.Type)
+ }
+ n.SetDiag(true)
+ }
+
+ // pick off before type-checking arguments
+ ok |= ctxExpr
+
+ // turn CALL(type, arg) into CONV(arg) w/ type
+ n.Left = nil
+
+ n.Op = OCONV
+ n.Type = l.Type
+ if !onearg(n, "conversion to %v", l.Type) {
+ n.Type = nil
+ return n
+ }
+ n = typecheck1(n, top)
+ return n
+ }
+
+ typecheckargs(n)
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ checkwidth(t)
+
+ switch l.Op {
+ case ODOTINTER:
+ n.Op = OCALLINTER
+
+ case ODOTMETH:
+ n.Op = OCALLMETH
+
+ // typecheckaste was used here but there wasn't enough
+ // information further down the call chain to know if we
+ // were testing a method receiver for unexported fields.
+ // It isn't necessary, so just do a sanity check.
+ tp := t.Recv().Type
+
+ if l.Left == nil || !types.Identical(l.Left.Type, tp) {
+ Fatalf("method receiver")
+ }
+
+ default:
+ n.Op = OCALLFUNC
+ if t.Etype != TFUNC {
+ name := l.String()
+ if isBuiltinFuncName(name) && l.Name.Defn != nil {
+ // be more specific when the function
+ // name matches a predeclared function
+ yyerror("cannot call non-function %s (type %v), declared at %s",
+ name, t, linestr(l.Name.Defn.Pos))
+ } else {
+ yyerror("cannot call non-function %s (type %v)", name, t)
+ }
+ n.Type = nil
+ return n
+ }
+ }
+
+ typecheckaste(OCALL, n.Left, n.IsDDD(), t.Params(), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) })
+ ok |= ctxStmt
+ if t.NumResults() == 0 {
+ break
+ }
+ ok |= ctxExpr
+ if t.NumResults() == 1 {
+ n.Type = l.Type.Results().Field(0).Type
+
+ if n.Op == OCALLFUNC && n.Left.Op == ONAME && isRuntimePkg(n.Left.Sym.Pkg) && n.Left.Sym.Name == "getg" {
+ // Emit code for runtime.getg() directly instead of calling function.
+ // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
+ // so that the ordering pass can make sure to preserve the semantics of the original code
+ // (in particular, the exact time of the function call) by introducing temporaries.
+ // In this case, we know getg() always returns the same result within a given function
+ // and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
+ n.Op = OGETG
+ }
+
+ break
+ }
+
+ // multiple return
+ if top&(ctxMultiOK|ctxStmt) == 0 {
+ yyerror("multiple-value %v() in single-value context", l)
+ break
+ }
+
+ n.Type = l.Type.Results()
+
+ case OALIGNOF, OOFFSETOF, OSIZEOF:
+ ok |= ctxExpr
+ if !onearg(n, "%v", n.Op) {
+ n.Type = nil
+ return n
+ }
+ n.Type = types.Types[TUINTPTR]
+
+ case OCAP, OLEN:
+ ok |= ctxExpr
+ if !onearg(n, "%v", n.Op) {
+ n.Type = nil
+ return n
+ }
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ n.Left = implicitstar(n.Left)
+ l := n.Left
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+
+ var ok bool
+ if n.Op == OLEN {
+ ok = okforlen[t.Etype]
+ } else {
+ ok = okforcap[t.Etype]
+ }
+ if !ok {
+ yyerror("invalid argument %L for %v", l, n.Op)
+ n.Type = nil
+ return n
+ }
+
+ n.Type = types.Types[TINT]
+
+ case OREAL, OIMAG:
+ ok |= ctxExpr
+ if !onearg(n, "%v", n.Op) {
+ n.Type = nil
+ return n
+ }
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ l := n.Left
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+
+ // Determine result type.
+ switch t.Etype {
+ case TIDEAL:
+ n.Type = types.UntypedFloat
+ case TCOMPLEX64:
+ n.Type = types.Types[TFLOAT32]
+ case TCOMPLEX128:
+ n.Type = types.Types[TFLOAT64]
+ default:
+ yyerror("invalid argument %L for %v", l, n.Op)
+ n.Type = nil
+ return n
+ }
+
+ case OCOMPLEX:
+ ok |= ctxExpr
+ typecheckargs(n)
+ if !twoarg(n) {
+ n.Type = nil
+ return n
+ }
+ l := n.Left
+ r := n.Right
+ if l.Type == nil || r.Type == nil {
+ n.Type = nil
+ return n
+ }
+ l, r = defaultlit2(l, r, false)
+ if l.Type == nil || r.Type == nil {
+ n.Type = nil
+ return n
+ }
+ n.Left = l
+ n.Right = r
+
+ if !types.Identical(l.Type, r.Type) {
+ yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
+ n.Type = nil
+ return n
+ }
+
+ var t *types.Type
+ switch l.Type.Etype {
+ default:
+ yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type)
+ n.Type = nil
+ return n
+
+ case TIDEAL:
+ t = types.UntypedComplex
+
+ case TFLOAT32:
+ t = types.Types[TCOMPLEX64]
+
+ case TFLOAT64:
+ t = types.Types[TCOMPLEX128]
+ }
+ n.Type = t
+
+ case OCLOSE:
+ if !onearg(n, "%v", n.Op) {
+ n.Type = nil
+ return n
+ }
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ l := n.Left
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if !t.IsChan() {
+ 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)
+ n.Type = nil
+ return n
+ }
+
+ ok |= ctxStmt
+
+ case ODELETE:
+ ok |= ctxStmt
+ typecheckargs(n)
+ args := n.List
+ if args.Len() == 0 {
+ yyerror("missing arguments to delete")
+ n.Type = nil
+ return n
+ }
+
+ if args.Len() == 1 {
+ yyerror("missing second (key) argument to delete")
+ n.Type = nil
+ return n
+ }
+
+ if args.Len() != 2 {
+ yyerror("too many arguments to delete")
+ n.Type = nil
+ return n
+ }
+
+ l := args.First()
+ r := args.Second()
+ if l.Type != nil && !l.Type.IsMap() {
+ yyerror("first argument to delete must be map; have %L", l.Type)
+ n.Type = nil
+ return n
+ }
+
+ args.SetSecond(assignconv(r, l.Type.Key(), "delete"))
+
+ case OAPPEND:
+ ok |= ctxExpr
+ typecheckargs(n)
+ args := n.List
+ if args.Len() == 0 {
+ yyerror("missing arguments to append")
+ n.Type = nil
+ return n
+ }
+
+ t := args.First().Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+
+ n.Type = t
+ if !t.IsSlice() {
+ if Isconst(args.First(), CTNIL) {
+ 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 %L", t)
+ n.Type = nil
+ return n
+ }
+
+ if n.IsDDD() {
+ if args.Len() == 1 {
+ yyerror("cannot use ... on first argument to append")
+ n.Type = nil
+ return n
+ }
+
+ if args.Len() != 2 {
+ yyerror("too many arguments to append")
+ n.Type = nil
+ return n
+ }
+
+ if t.Elem().IsKind(TUINT8) && args.Second().Type.IsString() {
+ args.SetSecond(defaultlit(args.Second(), types.Types[TSTRING]))
+ break
+ }
+
+ args.SetSecond(assignconv(args.Second(), t.Orig, "append"))
+ break
+ }
+
+ as := args.Slice()[1:]
+ for i, n := range as {
+ if n.Type == nil {
+ continue
+ }
+ as[i] = assignconv(n, t.Elem(), "append")
+ checkwidth(as[i].Type) // ensure width is calculated for backend
+ }
+
+ case OCOPY:
+ ok |= ctxStmt | ctxExpr
+ typecheckargs(n)
+ if !twoarg(n) {
+ n.Type = nil
+ return n
+ }
+ n.Type = types.Types[TINT]
+ if n.Left.Type == nil || n.Right.Type == nil {
+ n.Type = nil
+ return n
+ }
+ n.Left = defaultlit(n.Left, nil)
+ n.Right = defaultlit(n.Right, nil)
+ if n.Left.Type == nil || n.Right.Type == nil {
+ n.Type = nil
+ return n
+ }
+
+ // copy([]byte, string)
+ if n.Left.Type.IsSlice() && n.Right.Type.IsString() {
+ if types.Identical(n.Left.Type.Elem(), types.Bytetype) {
+ break
+ }
+ 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 %L, %L", n.Left.Type, n.Right.Type)
+ } else if !n.Left.Type.IsSlice() {
+ 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 %L", n.Right.Type)
+ }
+ n.Type = nil
+ return n
+ }
+
+ if !types.Identical(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
+ }
+
+ case OCONV:
+ ok |= ctxExpr
+ checkwidth(n.Type) // ensure width is calculated for backend
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = convlit1(n.Left, n.Type, true, nil)
+ t := n.Left.Type
+ if t == nil || n.Type == nil {
+ n.Type = nil
+ return n
+ }
+ var why string
+ n.Op, why = convertop(n.Left.Op == OLITERAL, t, n.Type)
+ if n.Op == OXXX {
+ if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() {
+ yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
+ n.SetDiag(true)
+ }
+ n.Op = OCONV
+ n.Type = nil
+ return n
+ }
+
+ switch n.Op {
+ case OCONVNOP:
+ if t.Etype == n.Type.Etype {
+ switch t.Etype {
+ case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128:
+ // Floating point casts imply rounding and
+ // so the conversion must be kept.
+ n.Op = OCONV
+ }
+ }
+
+ // do not convert to []byte literal. See CL 125796.
+ // generated code and compiler memory footprint is better without it.
+ case OSTR2BYTES:
+ break
+
+ case OSTR2RUNES:
+ if n.Left.Op == OLITERAL {
+ n = stringtoruneslit(n)
+ }
+ }
+
+ case OMAKE:
+ ok |= ctxExpr
+ args := n.List.Slice()
+ if len(args) == 0 {
+ yyerror("missing argument to make")
+ n.Type = nil
+ return n
+ }
+
+ n.List.Set(nil)
+ l := args[0]
+ l = typecheck(l, ctxType)
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+
+ i := 1
+ switch t.Etype {
+ default:
+ 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)
+ n.Type = nil
+ return n
+ }
+
+ l = args[i]
+ i++
+ l = typecheck(l, ctxExpr)
+ var r *Node
+ if i < len(args) {
+ r = args[i]
+ i++
+ r = typecheck(r, ctxExpr)
+ }
+
+ if l.Type == nil || (r != nil && r.Type == nil) {
+ n.Type = nil
+ return n
+ }
+ if !checkmake(t, "len", &l) || r != nil && !checkmake(t, "cap", &r) {
+ n.Type = nil
+ 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)
+ n.Type = nil
+ return n
+ }
+
+ n.Left = l
+ n.Right = r
+ n.Op = OMAKESLICE
+
+ case TMAP:
+ if i < len(args) {
+ l = args[i]
+ i++
+ l = typecheck(l, ctxExpr)
+ l = defaultlit(l, types.Types[TINT])
+ if l.Type == nil {
+ n.Type = nil
+ return n
+ }
+ if !checkmake(t, "size", &l) {
+ n.Type = nil
+ return n
+ }
+ n.Left = l
+ } else {
+ n.Left = nodintconst(0)
+ }
+ n.Op = OMAKEMAP
+
+ case TCHAN:
+ l = nil
+ if i < len(args) {
+ l = args[i]
+ i++
+ l = typecheck(l, ctxExpr)
+ l = defaultlit(l, types.Types[TINT])
+ if l.Type == nil {
+ n.Type = nil
+ return n
+ }
+ if !checkmake(t, "buffer", &l) {
+ n.Type = nil
+ return n
+ }
+ n.Left = l
+ } else {
+ n.Left = nodintconst(0)
+ }
+ n.Op = OMAKECHAN
+ }
+
+ if i < len(args) {
+ yyerror("too many arguments to make(%v)", t)
+ n.Op = OMAKE
+ n.Type = nil
+ return n
+ }
+
+ n.Type = t
+
+ case ONEW:
+ ok |= ctxExpr
+ args := n.List
+ if args.Len() == 0 {
+ yyerror("missing argument to new")
+ n.Type = nil
+ return n
+ }
+
+ l := args.First()
+ l = typecheck(l, ctxType)
+ t := l.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if args.Len() > 1 {
+ yyerror("too many arguments to new(%v)", t)
+ n.Type = nil
+ return n
+ }
+
+ n.Left = l
+ n.Type = types.NewPtr(t)
+
+ case OPRINT, OPRINTN:
+ ok |= ctxStmt
+ typecheckargs(n)
+ ls := n.List.Slice()
+ for i1, n1 := range ls {
+ // Special case for print: int constant is int64, not int.
+ if Isconst(n1, CTINT) {
+ ls[i1] = defaultlit(ls[i1], types.Types[TINT64])
+ } else {
+ ls[i1] = defaultlit(ls[i1], nil)
+ }
+ }
+
+ case OPANIC:
+ ok |= ctxStmt
+ if !onearg(n, "panic") {
+ n.Type = nil
+ return n
+ }
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, types.Types[TINTER])
+ if n.Left.Type == nil {
+ n.Type = nil
+ return n
+ }
+
+ case ORECOVER:
+ ok |= ctxExpr | ctxStmt
+ if n.List.Len() != 0 {
+ yyerror("too many arguments to recover")
+ n.Type = nil
+ return n
+ }
+
+ n.Type = types.Types[TINTER]
+
+ case OCLOSURE:
+ ok |= ctxExpr
+ typecheckclosure(n, top)
+ if n.Type == nil {
+ return n
+ }
+
+ case OITAB:
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ t := n.Left.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if !t.IsInterface() {
+ Fatalf("OITAB of %v", t)
+ }
+ n.Type = types.NewPtr(types.Types[TUINTPTR])
+
+ 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)
+
+ case OSPTR:
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ t := n.Left.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ if !t.IsSlice() && !t.IsString() {
+ Fatalf("OSPTR of %v", t)
+ }
+ if t.IsString() {
+ n.Type = types.NewPtr(types.Types[TUINT8])
+ } else {
+ n.Type = types.NewPtr(t.Elem())
+ }
+
+ case OCLOSUREVAR:
+ ok |= ctxExpr
+
+ case OCFUNC:
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Type = types.Types[TUINTPTR]
+
+ case OCONVNOP:
+ ok |= ctxExpr
+ n.Left = typecheck(n.Left, ctxExpr)
+
+ // statements
+ case OAS:
+ ok |= ctxStmt
+
+ typecheckas(n)
+
+ // Code that creates temps does not bother to set defn, so do it here.
+ if n.Left.Op == ONAME && n.Left.IsAutoTmp() {
+ n.Left.Name.Defn = n
+ }
+
+ case OAS2:
+ ok |= ctxStmt
+ typecheckas2(n)
+
+ case OBREAK,
+ OCONTINUE,
+ ODCL,
+ OEMPTY,
+ OGOTO,
+ OFALL,
+ OVARKILL,
+ OVARLIVE:
+ ok |= ctxStmt
+
+ case OLABEL:
+ ok |= ctxStmt
+ decldepth++
+ if n.Sym.IsBlank() {
+ // Empty identifier is valid but useless.
+ // Eliminate now to simplify life later.
+ // See issues 7538, 11589, 11593.
+ n.Op = OEMPTY
+ n.Left = nil
+ }
+
+ case ODEFER:
+ ok |= ctxStmt
+ n.Left = typecheck(n.Left, ctxStmt|ctxExpr)
+ if !n.Left.Diag() {
+ checkdefergo(n)
+ }
+
+ case OGO:
+ ok |= ctxStmt
+ n.Left = typecheck(n.Left, ctxStmt|ctxExpr)
+ checkdefergo(n)
+
+ case OFOR, OFORUNTIL:
+ ok |= ctxStmt
+ typecheckslice(n.Ninit.Slice(), ctxStmt)
+ decldepth++
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ if n.Left != nil {
+ t := n.Left.Type
+ if t != nil && !t.IsBoolean() {
+ yyerror("non-bool %L used as for condition", n.Left)
+ }
+ }
+ n.Right = typecheck(n.Right, ctxStmt)
+ if n.Op == OFORUNTIL {
+ typecheckslice(n.List.Slice(), ctxStmt)
+ }
+ typecheckslice(n.Nbody.Slice(), ctxStmt)
+ decldepth--
+
+ case OIF:
+ ok |= ctxStmt
+ typecheckslice(n.Ninit.Slice(), ctxStmt)
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ if n.Left != nil {
+ t := n.Left.Type
+ if t != nil && !t.IsBoolean() {
+ yyerror("non-bool %L used as if condition", n.Left)
+ }
+ }
+ typecheckslice(n.Nbody.Slice(), ctxStmt)
+ typecheckslice(n.Rlist.Slice(), ctxStmt)
+
+ case ORETURN:
+ ok |= ctxStmt
+ typecheckargs(n)
+ if Curfn == nil {
+ yyerror("return outside function")
+ n.Type = nil
+ return n
+ }
+
+ if Curfn.Type.FuncType().Outnamed && n.List.Len() == 0 {
+ break
+ }
+ typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" })
+
+ case ORETJMP:
+ ok |= ctxStmt
+
+ case OSELECT:
+ ok |= ctxStmt
+ typecheckselect(n)
+
+ case OSWITCH:
+ ok |= ctxStmt
+ typecheckswitch(n)
+
+ case ORANGE:
+ ok |= ctxStmt
+ typecheckrange(n)
+
+ case OTYPESW:
+ yyerror("use of .(type) outside type switch")
+ n.Type = nil
+ return n
+
+ case ODCLFUNC:
+ ok |= ctxStmt
+ typecheckfunc(n)
+
+ case ODCLCONST:
+ ok |= ctxStmt
+ n.Left = typecheck(n.Left, ctxExpr)
+
+ case ODCLTYPE:
+ ok |= ctxStmt
+ n.Left = typecheck(n.Left, ctxType)
+ checkwidth(n.Left.Type)
+ }
+
+ t := n.Type
+ if t != nil && !t.IsFuncArgStruct() && n.Op != OTYPE {
+ switch t.Etype {
+ case TFUNC, // might have TANY; wait until it's called
+ TANY, TFORW, TIDEAL, TNIL, TBLANK:
+ break
+
+ default:
+ checkwidth(t)
+ }
+ }
+
+ evconst(n)
+ if n.Op == OTYPE && top&ctxType == 0 {
+ if !n.Type.Broke() {
+ yyerror("type %v is not an expression", n.Type)
+ }
+ n.Type = nil
+ return n
+ }
+
+ if top&(ctxExpr|ctxType) == ctxType && n.Op != OTYPE {
+ yyerror("%v is not a type", n)
+ n.Type = nil
+ return n
+ }
+
+ // TODO(rsc): simplify
+ if (top&(ctxCallee|ctxExpr|ctxType) != 0) && top&ctxStmt == 0 && ok&(ctxExpr|ctxType|ctxCallee) == 0 {
+ yyerror("%v used as value", n)
+ n.Type = nil
+ return n
+ }
+
+ if (top&ctxStmt != 0) && top&(ctxCallee|ctxExpr|ctxType) == 0 && ok&ctxStmt == 0 {
+ if !n.Diag() {
+ yyerror("%v evaluated but not used", n)
+ n.SetDiag(true)
+ }
+
+ n.Type = nil
+ return n
+ }
+
+ return n
+}
+
+func typecheckargs(n *Node) {
+ if n.List.Len() != 1 || n.IsDDD() {
+ typecheckslice(n.List.Slice(), ctxExpr)
+ return
+ }
+
+ typecheckslice(n.List.Slice(), ctxExpr|ctxMultiOK)
+ t := n.List.First().Type
+ if t == nil || !t.IsFuncArgStruct() {
+ return
+ }
+
+ // Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
+
+ // Save n as n.Orig for fmt.go.
+ if n.Orig == n {
+ n.Orig = n.sepcopy()
+ }
+
+ as := nod(OAS2, nil, nil)
+ as.Rlist.AppendNodes(&n.List)
+
+ // If we're outside of function context, then this call will
+ // be executed during the generated init function. However,
+ // init.go hasn't yet created it. Instead, associate the
+ // temporary variables with dummyInitFn for now, and init.go
+ // will reassociate them later when it's appropriate.
+ static := Curfn == nil
+ if static {
+ Curfn = dummyInitFn
+ }
+ for _, f := range t.FieldSlice() {
+ t := temp(f.Type)
+ as.Ninit.Append(nod(ODCL, t, nil))
+ as.List.Append(t)
+ n.List.Append(t)
+ }
+ if static {
+ Curfn = nil
+ }
+
+ as = typecheck(as, ctxStmt)
+ n.Ninit.Append(as)
+}
+
+func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
+ t := r.Type
+ if t == nil {
+ return false
+ }
+ if !t.IsInteger() {
+ yyerror("invalid slice index %v (type %v)", r, t)
+ return false
+ }
+
+ if r.Op == OLITERAL {
+ if r.Int64Val() < 0 {
+ yyerror("invalid slice index %v (index must be non-negative)", r)
+ return false
+ } else if tp != nil && tp.NumElem() >= 0 && r.Int64Val() > 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.Int64Val() > int64(len(l.StringVal())) {
+ yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.StringVal()))
+ return false
+ } else if r.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ yyerror("invalid slice index %v (index too large)", r)
+ return false
+ }
+ }
+
+ return true
+}
+
+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)
+ return false
+ }
+
+ return true
+}
+
+func checkdefergo(n *Node) {
+ what := "defer"
+ if n.Op == OGO {
+ what = "go"
+ }
+
+ switch n.Left.Op {
+ // ok
+ case OCALLINTER,
+ OCALLMETH,
+ OCALLFUNC,
+ OCLOSE,
+ OCOPY,
+ ODELETE,
+ OPANIC,
+ OPRINT,
+ OPRINTN,
+ ORECOVER:
+ return
+
+ case OAPPEND,
+ OCAP,
+ OCOMPLEX,
+ OIMAG,
+ OLEN,
+ OMAKE,
+ OMAKESLICE,
+ OMAKECHAN,
+ OMAKEMAP,
+ ONEW,
+ OREAL,
+ OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
+ if n.Left.Orig != nil && n.Left.Orig.Op == OCONV {
+ break
+ }
+ yyerrorl(n.Pos, "%s discards result of %v", what, n.Left)
+ return
+ }
+
+ // type is broken or missing, most likely a method call on a broken type
+ // we will warn about the broken type elsewhere. no need to emit a potentially confusing error
+ if n.Left.Type == nil || n.Left.Type.Broke() {
+ return
+ }
+
+ if !n.Diag() {
+ // The syntax made sure it was a call, so this must be
+ // a conversion.
+ n.SetDiag(true)
+ yyerrorl(n.Pos, "%s requires function call, not conversion", what)
+ }
+}
+
+// The result of implicitstar MUST be assigned back to n, e.g.
+// n.Left = implicitstar(n.Left)
+func implicitstar(n *Node) *Node {
+ // insert implicit * if needed for fixed array
+ t := n.Type
+ if t == nil || !t.IsPtr() {
+ return n
+ }
+ t = t.Elem()
+ if t == nil {
+ return n
+ }
+ if !t.IsArray() {
+ return n
+ }
+ n = nod(ODEREF, n, nil)
+ n.SetImplicit(true)
+ n = typecheck(n, ctxExpr)
+ return n
+}
+
+func onearg(n *Node, f string, args ...interface{}) bool {
+ if n.Left != nil {
+ return true
+ }
+ if n.List.Len() == 0 {
+ p := fmt.Sprintf(f, args...)
+ 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)
+ n.Left = n.List.First()
+ n.List.Set(nil)
+ return false
+ }
+
+ n.Left = n.List.First()
+ n.List.Set(nil)
+ return true
+}
+
+func twoarg(n *Node) bool {
+ if n.Left != nil {
+ return true
+ }
+ if n.List.Len() != 2 {
+ if n.List.Len() < 2 {
+ yyerror("not enough arguments in call to %v", n)
+ } else {
+ yyerror("too many arguments in call to %v", n)
+ }
+ return false
+ }
+ n.Left = n.List.First()
+ n.Right = n.List.Second()
+ n.List.Set(nil)
+ return true
+}
+
+func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dostrcmp int) *types.Field {
+ var r *types.Field
+ for _, f := range fs.Slice() {
+ if dostrcmp != 0 && f.Sym.Name == s.Name {
+ return f
+ }
+ if dostrcmp == 2 && strings.EqualFold(f.Sym.Name, s.Name) {
+ return f
+ }
+ if f.Sym != s {
+ continue
+ }
+ if r != nil {
+ if errnode != nil {
+ yyerror("ambiguous selector %v", errnode)
+ } else if t.IsPtr() {
+ yyerror("ambiguous selector (%v).%v", t, s)
+ } else {
+ yyerror("ambiguous selector %v.%v", t, s)
+ }
+ break
+ }
+
+ r = f
+ }
+
+ return r
+}
+
+// typecheckMethodExpr checks selector expressions (ODOT) where the
+// base expression is a type expression (OTYPE).
+func typecheckMethodExpr(n *Node) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckMethodExpr", n)(&res)
+ }
+
+ t := n.Left.Type
+
+ // Compute the method set for t.
+ var ms *types.Fields
+ if t.IsInterface() {
+ ms = t.Fields()
+ } else {
+ mt := methtype(t)
+ if mt == nil {
+ yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
+ n.Type = nil
+ return n
+ }
+ expandmeth(mt)
+ ms = mt.AllMethods()
+
+ // The method expression T.m requires a wrapper when T
+ // is different from m's declared receiver type. We
+ // normally generate these wrappers while writing out
+ // runtime type descriptors, which is always done for
+ // types declared at package scope. However, we need
+ // to make sure to generate wrappers for anonymous
+ // receiver types too.
+ if mt.Sym == nil {
+ addsignat(t)
+ }
+ }
+
+ s := n.Sym
+ m := lookdot1(n, s, t, ms, 0)
+ if m == nil {
+ if lookdot1(n, s, t, ms, 1) != nil {
+ yyerror("%v undefined (cannot refer to unexported method %v)", n, s)
+ } else if _, ambig := dotpath(s, t, nil, false); ambig {
+ yyerror("%v undefined (ambiguous selector)", n) // method or field
+ } else {
+ yyerror("%v undefined (type %v has no method %v)", n, t, s)
+ }
+ n.Type = nil
+ return n
+ }
+
+ if !isMethodApplicable(t, m) {
+ yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, s)
+ n.Type = nil
+ return n
+ }
+
+ n.Op = ONAME
+ if n.Name == nil {
+ n.Name = new(Name)
+ }
+ n.Right = newname(n.Sym)
+ n.Sym = methodSym(t, n.Sym)
+ n.Type = methodfunc(m.Type, n.Left.Type)
+ n.Xoffset = 0
+ n.SetClass(PFUNC)
+ // methodSym already marked n.Sym as a function.
+
+ // Issue 25065. Make sure that we emit the symbol for a local method.
+ if Ctxt.Flag_dynlink && !inimport && (t.Sym == nil || t.Sym.Pkg == localpkg) {
+ makefuncsym(n.Sym)
+ }
+
+ return n
+}
+
+// isMethodApplicable reports whether method m can be called on a
+// value of type t. This is necessary because we compute a single
+// method set for both T and *T, but some *T methods are not
+// applicable to T receivers.
+func isMethodApplicable(t *types.Type, m *types.Field) bool {
+ return t.IsPtr() || !m.Type.Recv().Type.IsPtr() || isifacemethod(m.Type) || m.Embedded == 2
+}
+
+func derefall(t *types.Type) *types.Type {
+ for t != nil && t.IsPtr() {
+ t = t.Elem()
+ }
+ return t
+}
+
+func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
+ s := n.Sym
+
+ dowidth(t)
+ var f1 *types.Field
+ if t.IsStruct() || t.IsInterface() {
+ f1 = lookdot1(n, s, t, t.Fields(), dostrcmp)
+ }
+
+ var f2 *types.Field
+ if n.Left.Type == t || n.Left.Type.Sym == nil {
+ mt := methtype(t)
+ if mt != nil {
+ f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp)
+ }
+ }
+
+ if f1 != nil {
+ if dostrcmp > 1 || f1.Broke() {
+ // Already in the process of diagnosing an error.
+ return f1
+ }
+ if f2 != nil {
+ yyerror("%v is both field and method", n.Sym)
+ }
+ if f1.Offset == BADWIDTH {
+ Fatalf("lookdot badwidth %v %p", f1, f1)
+ }
+ n.Xoffset = f1.Offset
+ n.Type = f1.Type
+ if t.IsInterface() {
+ if n.Left.Type.IsPtr() {
+ n.Left = nod(ODEREF, n.Left, nil) // implicitstar
+ n.Left.SetImplicit(true)
+ n.Left = typecheck(n.Left, ctxExpr)
+ }
+
+ n.Op = ODOTINTER
+ } else {
+ n.SetOpt(f1)
+ }
+
+ return f1
+ }
+
+ if f2 != nil {
+ if dostrcmp > 1 {
+ // Already in the process of diagnosing an error.
+ return f2
+ }
+ tt := n.Left.Type
+ dowidth(tt)
+ rcvr := f2.Type.Recv().Type
+ if !types.Identical(rcvr, tt) {
+ if rcvr.IsPtr() && types.Identical(rcvr.Elem(), tt) {
+ checklvalue(n.Left, "call pointer method on")
+ n.Left = nod(OADDR, n.Left, nil)
+ n.Left.SetImplicit(true)
+ n.Left = typecheck(n.Left, ctxType|ctxExpr)
+ } else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
+ n.Left = nod(ODEREF, n.Left, nil)
+ n.Left.SetImplicit(true)
+ n.Left = typecheck(n.Left, ctxType|ctxExpr)
+ } else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) {
+ yyerror("calling method %v with receiver %L requires explicit dereference", n.Sym, n.Left)
+ for tt.IsPtr() {
+ // Stop one level early for method with pointer receiver.
+ if rcvr.IsPtr() && !tt.Elem().IsPtr() {
+ break
+ }
+ n.Left = nod(ODEREF, n.Left, nil)
+ n.Left.SetImplicit(true)
+ n.Left = typecheck(n.Left, ctxType|ctxExpr)
+ tt = tt.Elem()
+ }
+ } else {
+ Fatalf("method mismatch: %v for %v", rcvr, tt)
+ }
+ }
+
+ pll := n
+ ll := n.Left
+ for ll.Left != nil && (ll.Op == ODOT || ll.Op == ODOTPTR || ll.Op == ODEREF) {
+ pll = ll
+ ll = ll.Left
+ }
+ if pll.Implicit() && ll.Type.IsPtr() && ll.Type.Sym != nil && asNode(ll.Type.Sym.Def) != nil && asNode(ll.Type.Sym.Def).Op == OTYPE {
+ // It is invalid to automatically dereference a named pointer type when selecting a method.
+ // Make n.Left == ll to clarify error message.
+ n.Left = ll
+ return nil
+ }
+
+ n.Sym = methodSym(n.Left.Type, f2.Sym)
+ n.Xoffset = f2.Offset
+ n.Type = f2.Type
+ n.Op = ODOTMETH
+
+ return f2
+ }
+
+ return nil
+}
+
+func nokeys(l Nodes) bool {
+ for _, n := range l.Slice() {
+ if n.Op == OKEY || n.Op == OSTRUCTKEY {
+ return false
+ }
+ }
+ return true
+}
+
+func hasddd(t *types.Type) bool {
+ for _, tl := range t.Fields().Slice() {
+ if tl.IsDDD() {
+ return true
+ }
+ }
+
+ return false
+}
+
+// typecheck assignment: type list = expression list
+func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, desc func() string) {
+ var t *types.Type
+ var i int
+
+ lno := lineno
+ defer func() { lineno = lno }()
+
+ if tstruct.Broke() {
+ return
+ }
+
+ var n *Node
+ if nl.Len() == 1 {
+ n = nl.First()
+ }
+
+ n1 := tstruct.NumFields()
+ n2 := nl.Len()
+ if !hasddd(tstruct) {
+ if n2 > n1 {
+ goto toomany
+ }
+ if n2 < n1 {
+ goto notenough
+ }
+ } else {
+ if !isddd {
+ if n2 < n1-1 {
+ goto notenough
+ }
+ } else {
+ if n2 > n1 {
+ goto toomany
+ }
+ if n2 < n1 {
+ goto notenough
+ }
+ }
+ }
+
+ i = 0
+ for _, tl := range tstruct.Fields().Slice() {
+ t = tl.Type
+ if tl.IsDDD() {
+ if isddd {
+ if i >= nl.Len() {
+ goto notenough
+ }
+ if nl.Len()-i > 1 {
+ goto toomany
+ }
+ n = nl.Index(i)
+ setlineno(n)
+ if n.Type != nil {
+ nl.SetIndex(i, assignconvfn(n, t, desc))
+ }
+ return
+ }
+
+ // TODO(mdempsky): Make into ... call with implicit slice.
+ for ; i < nl.Len(); i++ {
+ n = nl.Index(i)
+ setlineno(n)
+ if n.Type != nil {
+ nl.SetIndex(i, assignconvfn(n, t.Elem(), desc))
+ }
+ }
+ return
+ }
+
+ if i >= nl.Len() {
+ goto notenough
+ }
+ n = nl.Index(i)
+ setlineno(n)
+ if n.Type != nil {
+ nl.SetIndex(i, assignconvfn(n, t, desc))
+ }
+ i++
+ }
+
+ if i < nl.Len() {
+ goto toomany
+ }
+ if isddd {
+ if call != nil {
+ yyerror("invalid use of ... in call to %v", call)
+ } else {
+ yyerror("invalid use of ... in %v", op)
+ }
+ }
+ return
+
+notenough:
+ if n == nil || (!n.Diag() && n.Type != nil) {
+ details := errorDetails(nl, tstruct, isddd)
+ if call != nil {
+ // call is the expression being called, not the overall call.
+ // Method expressions have the form T.M, and the compiler has
+ // rewritten those to ONAME nodes but left T in Left.
+ if call.isMethodExpression() {
+ yyerror("not enough arguments in call to method expression %v%s", call, details)
+ } else {
+ yyerror("not enough arguments in call to %v%s", call, details)
+ }
+ } else {
+ yyerror("not enough arguments to %v%s", op, details)
+ }
+ if n != nil {
+ n.SetDiag(true)
+ }
+ }
+ return
+
+toomany:
+ details := errorDetails(nl, tstruct, isddd)
+ if call != nil {
+ yyerror("too many arguments in call to %v%s", call, details)
+ } else {
+ yyerror("too many arguments to %v%s", op, details)
+ }
+}
+
+func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string {
+ // If we don't know any type at a call site, let's suppress any return
+ // message signatures. See Issue https://golang.org/issues/19012.
+ if tstruct == nil {
+ return ""
+ }
+ // If any node has an unknown type, suppress it as well
+ for _, n := range nl.Slice() {
+ if n.Type == nil {
+ return ""
+ }
+ }
+ return fmt.Sprintf("\n\thave %s\n\twant %v", nl.sigerr(isddd), tstruct)
+}
+
+// sigrepr is a type's representation to the outside world,
+// in string representations of return signatures
+// e.g in error messages about wrong arguments to return.
+func sigrepr(t *types.Type, isddd bool) string {
+ switch t {
+ case types.UntypedString:
+ return "string"
+ case types.UntypedBool:
+ return "bool"
+ }
+
+ if t.Etype == TIDEAL {
+ // "untyped number" is not commonly used
+ // outside of the compiler, so let's use "number".
+ // TODO(mdempsky): Revisit this.
+ return "number"
+ }
+
+ // Turn []T... argument to ...T for clearer error message.
+ if isddd {
+ if !t.IsSlice() {
+ Fatalf("bad type for ... argument: %v", t)
+ }
+ return "..." + t.Elem().String()
+ }
+ return t.String()
+}
+
+// sigerr returns the signature of the types at the call or return.
+func (nl Nodes) sigerr(isddd bool) string {
+ if nl.Len() < 1 {
+ return "()"
+ }
+
+ var typeStrings []string
+ for i, n := range nl.Slice() {
+ isdddArg := isddd && i == nl.Len()-1
+ typeStrings = append(typeStrings, sigrepr(n.Type, isdddArg))
+ }
+
+ return fmt.Sprintf("(%s)", strings.Join(typeStrings, ", "))
+}
+
+// type check composite
+func fielddup(name string, hash map[string]bool) {
+ if hash[name] {
+ yyerror("duplicate field name in struct literal: %s", name)
+ return
+ }
+ hash[name] = true
+}
+
+// iscomptype reports whether type t is a composite literal type.
+func iscomptype(t *types.Type) bool {
+ switch t.Etype {
+ case TARRAY, TSLICE, TSTRUCT, TMAP:
+ return true
+ default:
+ return false
+ }
+}
+
+// pushtype adds elided type information for composite literals if
+// appropriate, and returns the resulting expression.
+func pushtype(n *Node, t *types.Type) *Node {
+ if n == nil || n.Op != OCOMPLIT || n.Right != nil {
+ return n
+ }
+
+ switch {
+ case iscomptype(t):
+ // For T, return T{...}.
+ n.Right = typenod(t)
+
+ case t.IsPtr() && iscomptype(t.Elem()):
+ // For *T, return &T{...}.
+ n.Right = typenod(t.Elem())
+
+ n = nodl(n.Pos, OADDR, n, nil)
+ n.SetImplicit(true)
+ }
+
+ return n
+}
+
+// The result of typecheckcomplit MUST be assigned back to n, e.g.
+// n.Left = typecheckcomplit(n.Left)
+func typecheckcomplit(n *Node) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckcomplit", n)(&res)
+ }
+
+ lno := lineno
+ defer func() {
+ lineno = lno
+ }()
+
+ if n.Right == nil {
+ yyerrorl(n.Pos, "missing type in composite literal")
+ n.Type = nil
+ return n
+ }
+
+ // Save original node (including n.Right)
+ n.Orig = n.copy()
+
+ setlineno(n.Right)
+
+ // Need to handle [...]T arrays specially.
+ if n.Right.Op == OTARRAY && n.Right.Left != nil && n.Right.Left.Op == ODDD {
+ n.Right.Right = typecheck(n.Right.Right, ctxType)
+ if n.Right.Right.Type == nil {
+ n.Type = nil
+ return n
+ }
+ elemType := n.Right.Right.Type
+
+ length := typecheckarraylit(elemType, -1, n.List.Slice(), "array literal")
+
+ n.Op = OARRAYLIT
+ n.Type = types.NewArray(elemType, length)
+ n.Right = nil
+ return n
+ }
+
+ n.Right = typecheck(n.Right, ctxType)
+ t := n.Right.Type
+ if t == nil {
+ n.Type = nil
+ return n
+ }
+ n.Type = t
+
+ switch t.Etype {
+ default:
+ yyerror("invalid composite literal type %v", t)
+ n.Type = nil
+
+ case TARRAY:
+ typecheckarraylit(t.Elem(), t.NumElem(), n.List.Slice(), "array literal")
+ n.Op = OARRAYLIT
+ n.Right = nil
+
+ case TSLICE:
+ length := typecheckarraylit(t.Elem(), -1, n.List.Slice(), "slice literal")
+ n.Op = OSLICELIT
+ n.Right = nodintconst(length)
+
+ case TMAP:
+ var cs constSet
+ for i3, l := range n.List.Slice() {
+ setlineno(l)
+ if l.Op != OKEY {
+ n.List.SetIndex(i3, typecheck(l, ctxExpr))
+ yyerror("missing key in map literal")
+ continue
+ }
+
+ r := l.Left
+ r = pushtype(r, t.Key())
+ r = typecheck(r, ctxExpr)
+ l.Left = assignconv(r, t.Key(), "map key")
+ cs.add(lineno, l.Left, "key", "map literal")
+
+ r = l.Right
+ r = pushtype(r, t.Elem())
+ r = typecheck(r, ctxExpr)
+ l.Right = assignconv(r, t.Elem(), "map value")
+ }
+
+ n.Op = OMAPLIT
+ n.Right = nil
+
+ case TSTRUCT:
+ // Need valid field offsets for Xoffset below.
+ dowidth(t)
+
+ errored := false
+ if n.List.Len() != 0 && nokeys(n.List) {
+ // simple list of variables
+ ls := n.List.Slice()
+ for i, n1 := range ls {
+ setlineno(n1)
+ n1 = typecheck(n1, ctxExpr)
+ ls[i] = n1
+ if i >= t.NumFields() {
+ if !errored {
+ yyerror("too many values in %v", n)
+ errored = true
+ }
+ continue
+ }
+
+ f := t.Field(i)
+ s := f.Sym
+ if s != nil && !types.IsExported(s.Name) && s.Pkg != localpkg {
+ yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
+ }
+ // No pushtype allowed here. Must name fields for that.
+ n1 = assignconv(n1, f.Type, "field value")
+ n1 = nodSym(OSTRUCTKEY, n1, f.Sym)
+ n1.Xoffset = f.Offset
+ ls[i] = n1
+ }
+ if len(ls) < t.NumFields() {
+ yyerror("too few values in %v", n)
+ }
+ } else {
+ hash := make(map[string]bool)
+
+ // keyed list
+ ls := n.List.Slice()
+ for i, l := range ls {
+ setlineno(l)
+
+ 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 || key.Sym.IsBlank() {
+ yyerror("invalid field name %v in struct initializer", key)
+ l.Left = typecheck(l.Left, ctxExpr)
+ 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 && types.IsExported(s.Name) {
+ s1 := lookup(s.Name)
+ if s1.Origpkg == s.Pkg {
+ s = s1
+ }
+ }
+ l.Sym = s
+ }
+
+ if l.Op != OSTRUCTKEY {
+ if !errored {
+ yyerror("mixture of field:value and value initializers")
+ errored = true
+ }
+ ls[i] = typecheck(ls[i], ctxExpr)
+ continue
+ }
+
+ f := lookdot1(nil, l.Sym, t, t.Fields(), 0)
+ if f == nil {
+ if ci := lookdot1(nil, l.Sym, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
+ if visible(ci.Sym) {
+ yyerror("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym, t, ci.Sym)
+ } else if nonexported(l.Sym) && l.Sym.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
+ yyerror("cannot refer to unexported field '%v' in struct literal of type %v", l.Sym, t)
+ } else {
+ yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t)
+ }
+ continue
+ }
+ var f *types.Field
+ p, _ := dotpath(l.Sym, t, &f, true)
+ if p == nil || f.IsMethod() {
+ yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t)
+ continue
+ }
+ // dotpath returns the parent embedded types in reverse order.
+ var ep []string
+ for ei := len(p) - 1; ei >= 0; ei-- {
+ ep = append(ep, p[ei].field.Sym.Name)
+ }
+ ep = append(ep, l.Sym.Name)
+ yyerror("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), t)
+ continue
+ }
+ fielddup(f.Sym.Name, hash)
+ l.Xoffset = f.Offset
+
+ // No pushtype allowed here. Tried and rejected.
+ l.Left = typecheck(l.Left, ctxExpr)
+ l.Left = assignconv(l.Left, f.Type, "field value")
+ }
+ }
+
+ n.Op = OSTRUCTLIT
+ n.Right = nil
+ }
+
+ return n
+}
+
+// typecheckarraylit type-checks a sequence of slice/array literal elements.
+func typecheckarraylit(elemType *types.Type, bound int64, elts []*Node, ctx string) int64 {
+ // 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 _, elt := range elts {
+ if elt.Op == OKEY {
+ indices = make(map[int64]bool)
+ break
+ }
+ }
+
+ var key, length int64
+ for i, elt := range elts {
+ setlineno(elt)
+ vp := &elts[i]
+ if elt.Op == OKEY {
+ elt.Left = typecheck(elt.Left, ctxExpr)
+ key = indexconst(elt.Left)
+ if key < 0 {
+ if !elt.Left.Diag() {
+ if key == -2 {
+ yyerror("index too large")
+ } else {
+ yyerror("index must be non-negative integer constant")
+ }
+ elt.Left.SetDiag(true)
+ }
+ key = -(1 << 30) // stay negative for a while
+ }
+ vp = &elt.Right
+ }
+
+ r := *vp
+ r = pushtype(r, elemType)
+ r = typecheck(r, ctxExpr)
+ *vp = assignconv(r, elemType, ctx)
+
+ if key >= 0 {
+ if indices != nil {
+ if indices[key] {
+ yyerror("duplicate index in %s: %d", ctx, key)
+ } else {
+ indices[key] = true
+ }
+ }
+
+ if bound >= 0 && key >= bound {
+ yyerror("array index %d out of bounds [0:%d]", key, bound)
+ bound = -1
+ }
+ }
+
+ key++
+ if key > length {
+ length = key
+ }
+ }
+
+ return length
+}
+
+// visible reports whether sym is exported or locally defined.
+func visible(sym *types.Sym) bool {
+ return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg)
+}
+
+// nonexported reports whether sym is an unexported field.
+func nonexported(sym *types.Sym) bool {
+ return sym != nil && !types.IsExported(sym.Name)
+}
+
+// lvalue etc
+func islvalue(n *Node) bool {
+ switch n.Op {
+ case OINDEX:
+ if n.Left.Type != nil && n.Left.Type.IsArray() {
+ return islvalue(n.Left)
+ }
+ if n.Left.Type != nil && n.Left.Type.IsString() {
+ return false
+ }
+ fallthrough
+ case ODEREF, ODOTPTR, OCLOSUREVAR:
+ return true
+
+ case ODOT:
+ return islvalue(n.Left)
+
+ case ONAME:
+ if n.Class() == PFUNC {
+ return false
+ }
+ return true
+ }
+
+ return false
+}
+
+func checklvalue(n *Node, verb string) {
+ if !islvalue(n) {
+ yyerror("cannot %s %v", verb, n)
+ }
+}
+
+func checkassign(stmt *Node, n *Node) {
+ // Variables declared in ORANGE are assigned on every iteration.
+ if n.Name == nil || n.Name.Defn != stmt || stmt.Op == ORANGE {
+ r := outervalue(n)
+ if r.Op == ONAME {
+ r.Name.SetAssigned(true)
+ if r.Name.IsClosureVar() {
+ r.Name.Defn.Name.SetAssigned(true)
+ }
+ }
+ }
+
+ if islvalue(n) {
+ return
+ }
+ if n.Op == OINDEXMAP {
+ n.SetIndexMapLValue(true)
+ return
+ }
+
+ // have already complained about n being invalid
+ if n.Type == nil {
+ return
+ }
+
+ switch {
+ case n.Op == ODOT && n.Left.Op == OINDEXMAP:
+ yyerror("cannot assign to struct field %v in map", n)
+ case (n.Op == OINDEX && n.Left.Type.IsString()) || n.Op == OSLICESTR:
+ yyerror("cannot assign to %v (strings are immutable)", n)
+ case n.Op == OLITERAL && n.Sym != nil && n.isGoConst():
+ yyerror("cannot assign to %v (declared const)", n)
+ default:
+ yyerror("cannot assign to %v", n)
+ }
+ n.Type = nil
+}
+
+func checkassignlist(stmt *Node, l Nodes) {
+ for _, n := range l.Slice() {
+ checkassign(stmt, n)
+ }
+}
+
+// samesafeexpr checks whether it is safe to reuse one of l and r
+// instead of computing both. samesafeexpr assumes that l and r are
+// used in the same statement or expression. In order for it to be
+// safe to reuse l or r, they must:
+// * be the same expression
+// * not have side-effects (no function calls, no channel ops);
+// however, panics are ok
+// * not cause inappropriate aliasing; e.g. two string to []byte
+// conversions, must result in two distinct slices
+//
+// The handling of OINDEXMAP is subtle. OINDEXMAP can occur both
+// as an lvalue (map assignment) and an rvalue (map access). This is
+// currently OK, since the only place samesafeexpr gets used on an
+// lvalue expression is for OSLICE and OAPPEND optimizations, and it
+// is correct in those settings.
+func samesafeexpr(l *Node, r *Node) bool {
+ if l.Op != r.Op || !types.Identical(l.Type, r.Type) {
+ return false
+ }
+
+ switch l.Op {
+ case ONAME, OCLOSUREVAR:
+ return l == r
+
+ case ODOT, ODOTPTR:
+ return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left)
+
+ case ODEREF, OCONVNOP,
+ ONOT, OBITNOT, OPLUS, ONEG:
+ 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, OINDEXMAP,
+ OADD, OSUB, OOR, OXOR, OMUL, OLSH, ORSH, OAND, OANDNOT, ODIV, OMOD:
+ return samesafeexpr(l.Left, r.Left) && samesafeexpr(l.Right, r.Right)
+
+ case OLITERAL:
+ return eqval(l.Val(), r.Val())
+ }
+
+ return false
+}
+
+// type check assignment.
+// if this assignment is the definition of a var on the left side,
+// fill in the var's type.
+func typecheckas(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckas", n)(nil)
+ }
+
+ // delicate little dance.
+ // the definition of n may refer to this assignment
+ // as its definition, in which case it will call typecheckas.
+ // in that case, do not call typecheck back, or it will cycle.
+ // if the variable has a type (ntype) then typechecking
+ // will not look at defn, so it is okay (and desirable,
+ // so that the conversion below happens).
+ n.Left = resolve(n.Left)
+
+ if n.Left.Name == nil || n.Left.Name.Defn != n || n.Left.Name.Param.Ntype != nil {
+ n.Left = typecheck(n.Left, ctxExpr|ctxAssign)
+ }
+
+ // Use ctxMultiOK so we can emit an "N variables but M values" error
+ // to be consistent with typecheckas2 (#26616).
+ n.Right = typecheck(n.Right, ctxExpr|ctxMultiOK)
+ checkassign(n, n.Left)
+ if n.Right != nil && n.Right.Type != nil {
+ if n.Right.Type.IsFuncArgStruct() {
+ yyerror("assignment mismatch: 1 variable but %v returns %d values", n.Right.Left, n.Right.Type.NumFields())
+ // Multi-value RHS isn't actually valid for OAS; nil out
+ // to indicate failed typechecking.
+ n.Right.Type = nil
+ } else if n.Left.Type != nil {
+ n.Right = assignconv(n.Right, n.Left.Type, "assignment")
+ }
+ }
+
+ if n.Left.Name != nil && n.Left.Name.Defn == n && n.Left.Name.Param.Ntype == nil {
+ n.Right = defaultlit(n.Right, nil)
+ n.Left.Type = n.Right.Type
+ }
+
+ // second half of dance.
+ // now that right is done, typecheck the left
+ // just to get it over with. see dance above.
+ n.SetTypecheck(1)
+
+ if n.Left.Typecheck() == 0 {
+ n.Left = typecheck(n.Left, ctxExpr|ctxAssign)
+ }
+ if !n.Left.isBlank() {
+ checkwidth(n.Left.Type) // ensure width is calculated for backend
+ }
+}
+
+func checkassignto(src *types.Type, dst *Node) {
+ if op, why := assignop(src, dst.Type); op == OXXX {
+ yyerror("cannot assign %v to %L in multiple assignment%s", src, dst, why)
+ return
+ }
+}
+
+func typecheckas2(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckas2", n)(nil)
+ }
+
+ ls := n.List.Slice()
+ for i1, n1 := range ls {
+ // delicate little dance.
+ n1 = resolve(n1)
+ ls[i1] = n1
+
+ if n1.Name == nil || n1.Name.Defn != n || n1.Name.Param.Ntype != nil {
+ ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
+ }
+ }
+
+ cl := n.List.Len()
+ cr := n.Rlist.Len()
+ if cl > 1 && cr == 1 {
+ n.Rlist.SetFirst(typecheck(n.Rlist.First(), ctxExpr|ctxMultiOK))
+ } else {
+ typecheckslice(n.Rlist.Slice(), ctxExpr)
+ }
+ checkassignlist(n, n.List)
+
+ var l *Node
+ var r *Node
+ if cl == cr {
+ // easy
+ ls := n.List.Slice()
+ rs := n.Rlist.Slice()
+ for il, nl := range ls {
+ nr := rs[il]
+ if nl.Type != nil && nr.Type != nil {
+ rs[il] = assignconv(nr, nl.Type, "assignment")
+ }
+ if nl.Name != nil && nl.Name.Defn == n && nl.Name.Param.Ntype == nil {
+ rs[il] = defaultlit(rs[il], nil)
+ nl.Type = rs[il].Type
+ }
+ }
+
+ goto out
+ }
+
+ l = n.List.First()
+ r = n.Rlist.First()
+
+ // x,y,z = f()
+ if cr == 1 {
+ if r.Type == nil {
+ goto out
+ }
+ switch r.Op {
+ case OCALLMETH, OCALLINTER, OCALLFUNC:
+ if !r.Type.IsFuncArgStruct() {
+ break
+ }
+ cr = r.Type.NumFields()
+ if cr != cl {
+ goto mismatch
+ }
+ n.Op = OAS2FUNC
+ n.Right = r
+ n.Rlist.Set(nil)
+ for i, l := range n.List.Slice() {
+ f := r.Type.Field(i)
+ if f.Type != nil && l.Type != nil {
+ checkassignto(f.Type, l)
+ }
+ if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil {
+ l.Type = f.Type
+ }
+ }
+ goto out
+ }
+ }
+
+ // x, ok = y
+ if cl == 2 && cr == 1 {
+ if r.Type == nil {
+ goto out
+ }
+ switch r.Op {
+ case OINDEXMAP, ORECV, ODOTTYPE:
+ switch r.Op {
+ case OINDEXMAP:
+ n.Op = OAS2MAPR
+ case ORECV:
+ n.Op = OAS2RECV
+ case ODOTTYPE:
+ n.Op = OAS2DOTTYPE
+ r.Op = ODOTTYPE2
+ }
+ n.Right = r
+ n.Rlist.Set(nil)
+ if l.Type != nil {
+ checkassignto(r.Type, l)
+ }
+ if l.Name != nil && l.Name.Defn == n {
+ l.Type = r.Type
+ }
+ l := n.List.Second()
+ if l.Type != nil && !l.Type.IsBoolean() {
+ checkassignto(types.Types[TBOOL], l)
+ }
+ if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil {
+ l.Type = types.Types[TBOOL]
+ }
+ goto out
+ }
+ }
+
+mismatch:
+ switch r.Op {
+ default:
+ yyerror("assignment mismatch: %d variables but %d values", cl, cr)
+ case OCALLFUNC, OCALLMETH, OCALLINTER:
+ yyerror("assignment mismatch: %d variables but %v returns %d values", cl, r.Left, cr)
+ }
+
+ // second half of dance
+out:
+ n.SetTypecheck(1)
+ ls = n.List.Slice()
+ for i1, n1 := range ls {
+ if n1.Typecheck() == 0 {
+ ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
+ }
+ }
+}
+
+// type check function definition
+func typecheckfunc(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckfunc", n)(nil)
+ }
+
+ 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, ctxExpr|ctxAssign)
+ t := n.Func.Nname.Type
+ if t == nil {
+ return
+ }
+ n.Type = t
+ t.FuncType().Nname = asTypesNode(n.Func.Nname)
+ rcvr := t.Recv()
+ if rcvr != nil && n.Func.Shortname != nil {
+ m := addmethod(n.Func.Shortname, t, true, n.Func.Pragma&Nointerface != 0)
+ if m == nil {
+ return
+ }
+
+ n.Func.Nname.Sym = methodSym(rcvr.Type, n.Func.Shortname)
+ declare(n.Func.Nname, PFUNC)
+ }
+
+ if Ctxt.Flag_dynlink && !inimport && n.Func.Nname != nil {
+ makefuncsym(n.Func.Nname.Sym)
+ }
+}
+
+// The result of stringtoruneslit MUST be assigned back to n, e.g.
+// n.Left = stringtoruneslit(n.Left)
+func stringtoruneslit(n *Node) *Node {
+ if n.Left.Op != OLITERAL || n.Left.Val().Ctype() != CTSTR {
+ Fatalf("stringtoarraylit %v", n)
+ }
+
+ var l []*Node
+ i := 0
+ for _, r := range n.Left.StringVal() {
+ l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(r))))
+ i++
+ }
+
+ nn := nod(OCOMPLIT, nil, typenod(n.Type))
+ nn.List.Set(l)
+ nn = typecheck(nn, ctxExpr)
+ return nn
+}
+
+var mapqueue []*Node
+
+func checkMapKeys() {
+ for _, n := range mapqueue {
+ k := n.Type.MapType().Key
+ if !k.Broke() && !IsComparable(k) {
+ yyerrorl(n.Pos, "invalid map key type %v", k)
+ }
+ }
+ mapqueue = nil
+}
+
+func setUnderlying(t, underlying *types.Type) {
+ if underlying.Etype == TFORW {
+ // This type isn't computed yet; when it is, update n.
+ underlying.ForwardType().Copyto = append(underlying.ForwardType().Copyto, t)
+ return
+ }
+
+ n := asNode(t.Nod)
+ ft := t.ForwardType()
+ cache := t.Cache
+
+ // TODO(mdempsky): Fix Type rekinding.
+ *t = *underlying
+
+ // Restore unnecessarily clobbered attributes.
+ t.Nod = asTypesNode(n)
+ t.Sym = n.Sym
+ if n.Name != nil {
+ t.Vargen = n.Name.Vargen
+ }
+ t.Cache = cache
+ t.SetDeferwidth(false)
+
+ // spec: "The declared type does not inherit any methods bound
+ // to the existing type, but the method set of an interface
+ // type [...] remains unchanged."
+ if !t.IsInterface() {
+ *t.Methods() = types.Fields{}
+ *t.AllMethods() = types.Fields{}
+ }
+
+ // 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.SetNotInHeap(true)
+ }
+
+ // Update types waiting on this type.
+ for _, w := range ft.Copyto {
+ setUnderlying(w, t)
+ }
+
+ // Double-check use of type as embedded type.
+ if ft.Embedlineno.IsKnown() {
+ if t.IsPtr() || t.IsUnsafePtr() {
+ yyerrorl(ft.Embedlineno, "embedded type cannot be a pointer")
+ }
+ }
+}
+
+func typecheckdeftype(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckdeftype", n)(nil)
+ }
+
+ n.SetTypecheck(1)
+ n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, ctxType)
+ t := n.Name.Param.Ntype.Type
+ if t == nil {
+ n.SetDiag(true)
+ n.Type = nil
+ } else if n.Type == nil {
+ n.SetDiag(true)
+ } else {
+ // copy new type and clear fields
+ // that don't come along.
+ setUnderlying(n.Type, t)
+ }
+}
+
+func typecheckdef(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckdef", n)(nil)
+ }
+
+ lno := setlineno(n)
+
+ if n.Op == ONONAME {
+ if !n.Diag() {
+ n.SetDiag(true)
+
+ // Note: adderrorname looks for this string and
+ // adds context about the outer expression
+ yyerrorl(lineno, "undefined: %v", n.Sym)
+ }
+ lineno = lno
+ return
+ }
+
+ if n.Walkdef() == 1 {
+ lineno = lno
+ return
+ }
+
+ typecheckdefstack = append(typecheckdefstack, n)
+ if n.Walkdef() == 2 {
+ flusherrors()
+ fmt.Printf("typecheckdef loop:")
+ for i := len(typecheckdefstack) - 1; i >= 0; i-- {
+ n := typecheckdefstack[i]
+ fmt.Printf(" %v", n.Sym)
+ }
+ fmt.Printf("\n")
+ Fatalf("typecheckdef loop")
+ }
+
+ n.SetWalkdef(2)
+
+ if n.Type != nil || n.Sym == nil { // builtin or no name
+ goto ret
+ }
+
+ switch n.Op {
+ default:
+ Fatalf("typecheckdef %v", n.Op)
+
+ case OLITERAL:
+ if n.Name.Param.Ntype != nil {
+ n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, ctxType)
+ n.Type = n.Name.Param.Ntype.Type
+ n.Name.Param.Ntype = nil
+ if n.Type == nil {
+ n.SetDiag(true)
+ goto ret
+ }
+ }
+
+ e := n.Name.Defn
+ n.Name.Defn = nil
+ if e == nil {
+ Dump("typecheckdef nil defn", n)
+ yyerrorl(n.Pos, "xxx")
+ }
+
+ e = typecheck(e, ctxExpr)
+ if e.Type == nil {
+ goto ret
+ }
+ if !e.isGoConst() {
+ if !e.Diag() {
+ if Isconst(e, CTNIL) {
+ yyerrorl(n.Pos, "const initializer cannot be nil")
+ } else {
+ yyerrorl(n.Pos, "const initializer %v is not a constant", e)
+ }
+ e.SetDiag(true)
+ }
+ goto ret
+ }
+
+ t := n.Type
+ if t != nil {
+ if !okforconst[t.Etype] {
+ yyerrorl(n.Pos, "invalid constant type %v", t)
+ goto ret
+ }
+
+ if !e.Type.IsUntyped() && !types.Identical(t, e.Type) {
+ yyerrorl(n.Pos, "cannot use %L as type %v in const initializer", e, t)
+ goto ret
+ }
+
+ e = convlit(e, t)
+ }
+
+ n.SetVal(e.Val())
+ n.Type = e.Type
+
+ case ONAME:
+ if n.Name.Param.Ntype != nil {
+ n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, ctxType)
+ n.Type = n.Name.Param.Ntype.Type
+ if n.Type == nil {
+ n.SetDiag(true)
+ goto ret
+ }
+ }
+
+ if n.Type != nil {
+ break
+ }
+ if n.Name.Defn == nil {
+ if n.SubOp() != 0 { // like OPRINTN
+ break
+ }
+ if nsavederrors+nerrors > 0 {
+ // Can have undefined variables in x := foo
+ // that make x have an n.name.Defn == nil.
+ // If there are other errors anyway, don't
+ // bother adding to the noise.
+ break
+ }
+
+ Fatalf("var without type, init: %v", n.Sym)
+ }
+
+ if n.Name.Defn.Op == ONAME {
+ n.Name.Defn = typecheck(n.Name.Defn, ctxExpr)
+ n.Type = n.Name.Defn.Type
+ break
+ }
+
+ n.Name.Defn = typecheck(n.Name.Defn, ctxStmt) // fills in n.Type
+
+ case OTYPE:
+ if p := n.Name.Param; p.Alias() {
+ // Type alias declaration: Simply use the rhs type - no need
+ // to create a new type.
+ // If we have a syntax error, p.Ntype may be nil.
+ if p.Ntype != nil {
+ p.Ntype = typecheck(p.Ntype, ctxType)
+ n.Type = p.Ntype.Type
+ if n.Type == nil {
+ n.SetDiag(true)
+ goto ret
+ }
+ // For package-level type aliases, set n.Sym.Def so we can identify
+ // it as a type alias during export. See also #31959.
+ if n.Name.Curfn == nil {
+ n.Sym.Def = asTypesNode(p.Ntype)
+ }
+ }
+ break
+ }
+
+ // regular type declaration
+ defercheckwidth()
+ n.SetWalkdef(1)
+ setTypeNode(n, types.New(TFORW))
+ n.Type.Sym = n.Sym
+ nerrors0 := nerrors
+ typecheckdeftype(n)
+ if n.Type.Etype == TFORW && nerrors > nerrors0 {
+ // Something went wrong during type-checking,
+ // but it was reported. Silence future errors.
+ n.Type.SetBroke(true)
+ }
+ resumecheckwidth()
+ }
+
+ret:
+ if n.Op != OLITERAL && n.Type != nil && n.Type.IsUntyped() {
+ Fatalf("got %v for %v", n.Type, n)
+ }
+ last := len(typecheckdefstack) - 1
+ if typecheckdefstack[last] != n {
+ Fatalf("typecheckdefstack mismatch")
+ }
+ typecheckdefstack[last] = nil
+ typecheckdefstack = typecheckdefstack[:last]
+
+ lineno = lno
+ n.SetWalkdef(1)
+}
+
+func checkmake(t *types.Type, arg string, np **Node) bool {
+ n := *np
+ if !n.Type.IsInteger() && n.Type.Etype != TIDEAL {
+ yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
+ return false
+ }
+
+ // Do range checks for constants before defaultlit
+ // to avoid redundant "constant NNN overflows int" errors.
+ switch consttype(n) {
+ case CTINT, CTRUNE, CTFLT, CTCPLX:
+ v := toint(n.Val()).U.(*Mpint)
+ if v.CmpInt64(0) < 0 {
+ yyerror("negative %s argument in make(%v)", arg, t)
+ return false
+ }
+ if v.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.
+ // TODO(gri) The length argument requirements for (array/slice) make
+ // are the same as for index expressions. Factor the code better;
+ // for instance, indexlit might be called here and incorporate some
+ // of the bounds checks done for make.
+ n = defaultlit(n, types.Types[TINT])
+ *np = n
+
+ return true
+}
+
+func markbreak(n *Node, implicit *Node) {
+ if n == nil {
+ return
+ }
+
+ switch n.Op {
+ case OBREAK:
+ if n.Sym == nil {
+ if implicit != nil {
+ implicit.SetHasBreak(true)
+ }
+ } else {
+ lab := asNode(n.Sym.Label)
+ if lab != nil {
+ lab.SetHasBreak(true)
+ }
+ }
+ case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE:
+ implicit = n
+ fallthrough
+ default:
+ markbreak(n.Left, implicit)
+ markbreak(n.Right, implicit)
+ markbreaklist(n.Ninit, implicit)
+ markbreaklist(n.Nbody, implicit)
+ markbreaklist(n.List, implicit)
+ markbreaklist(n.Rlist, implicit)
+ }
+}
+
+func markbreaklist(l 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, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE:
+ n.Sym.Label = asTypesNode(n.Name.Defn)
+ markbreak(n.Name.Defn, n.Name.Defn)
+ n.Sym.Label = nil
+ i++
+ continue
+ }
+ }
+
+ markbreak(n, implicit)
+ }
+}
+
+// isterminating reports whether the Nodes list ends with a terminating statement.
+func (l Nodes) isterminating() bool {
+ s := l.Slice()
+ c := len(s)
+ if c == 0 {
+ return false
+ }
+ return s[c-1].isterminating()
+}
+
+// Isterminating reports whether the node n, the last one in a
+// statement list, is a terminating statement.
+func (n *Node) isterminating() bool {
+ switch n.Op {
+ // NOTE: OLABEL is treated as a separate statement,
+ // not a separate prefix, so skipping to the last statement
+ // in the block handles the labeled statement case by
+ // skipping over the label. No case OLABEL here.
+
+ case OBLOCK:
+ return n.List.isterminating()
+
+ case OGOTO, ORETURN, ORETJMP, OPANIC, OFALL:
+ return true
+
+ case OFOR, OFORUNTIL:
+ if n.Left != nil {
+ return false
+ }
+ if n.HasBreak() {
+ return false
+ }
+ return true
+
+ case OIF:
+ return n.Nbody.isterminating() && n.Rlist.isterminating()
+
+ case OSWITCH, OTYPESW, OSELECT:
+ if n.HasBreak() {
+ return false
+ }
+ def := false
+ for _, n1 := range n.List.Slice() {
+ if !n1.Nbody.isterminating() {
+ return false
+ }
+ if n1.List.Len() == 0 { // default
+ def = true
+ }
+ }
+
+ if n.Op != OSELECT && !def {
+ return false
+ }
+ return true
+ }
+
+ return false
+}
+
+// checkreturn makes sure that fn terminates appropriately.
+func checkreturn(fn *Node) {
+ if fn.Type.NumResults() != 0 && fn.Nbody.Len() != 0 {
+ markbreaklist(fn.Nbody, nil)
+ if !fn.Nbody.isterminating() {
+ yyerrorl(fn.Func.Endlineno, "missing return at end of function")
+ }
+ }
+}
+
+func deadcode(fn *Node) {
+ deadcodeslice(fn.Nbody)
+ deadcodefn(fn)
+}
+
+func deadcodefn(fn *Node) {
+ if fn.Nbody.Len() == 0 {
+ return
+ }
+
+ for _, n := range fn.Nbody.Slice() {
+ if n.Ninit.Len() > 0 {
+ return
+ }
+ switch n.Op {
+ case OIF:
+ if !Isconst(n.Left, CTBOOL) || n.Nbody.Len() > 0 || n.Rlist.Len() > 0 {
+ return
+ }
+ case OFOR:
+ if !Isconst(n.Left, CTBOOL) || n.Left.BoolVal() {
+ return
+ }
+ default:
+ return
+ }
+ }
+
+ fn.Nbody.Set([]*Node{nod(OEMPTY, nil, nil)})
+}
+
+func deadcodeslice(nn Nodes) {
+ var lastLabel = -1
+ for i, n := range nn.Slice() {
+ if n != nil && n.Op == OLABEL {
+ lastLabel = i
+ }
+ }
+ for i, n := range nn.Slice() {
+ // Cut is set to true when all nodes after i'th position
+ // should be removed.
+ // In other words, it marks whole slice "tail" as dead.
+ cut := false
+ if n == nil {
+ continue
+ }
+ if n.Op == OIF {
+ n.Left = deadcodeexpr(n.Left)
+ if Isconst(n.Left, CTBOOL) {
+ var body Nodes
+ if n.Left.BoolVal() {
+ n.Rlist = Nodes{}
+ body = n.Nbody
+ } else {
+ n.Nbody = Nodes{}
+ body = n.Rlist
+ }
+ // If "then" or "else" branch ends with panic or return statement,
+ // it is safe to remove all statements after this node.
+ // isterminating is not used to avoid goto-related complications.
+ // We must be careful not to deadcode-remove labels, as they
+ // might be the target of a goto. See issue 28616.
+ if body := body.Slice(); len(body) != 0 {
+ switch body[(len(body) - 1)].Op {
+ case ORETURN, ORETJMP, OPANIC:
+ if i > lastLabel {
+ cut = true
+ }
+ }
+ }
+ }
+ }
+
+ deadcodeslice(n.Ninit)
+ deadcodeslice(n.Nbody)
+ deadcodeslice(n.List)
+ deadcodeslice(n.Rlist)
+ if cut {
+ *nn.slice = nn.Slice()[:i+1]
+ break
+ }
+ }
+}
+
+func deadcodeexpr(n *Node) *Node {
+ // Perform dead-code elimination on short-circuited boolean
+ // expressions involving constants with the intent of
+ // producing a constant 'if' condition.
+ switch n.Op {
+ case OANDAND:
+ n.Left = deadcodeexpr(n.Left)
+ n.Right = deadcodeexpr(n.Right)
+ if Isconst(n.Left, CTBOOL) {
+ if n.Left.BoolVal() {
+ return n.Right // true && x => x
+ } else {
+ return n.Left // false && x => false
+ }
+ }
+ case OOROR:
+ n.Left = deadcodeexpr(n.Left)
+ n.Right = deadcodeexpr(n.Right)
+ if Isconst(n.Left, CTBOOL) {
+ if n.Left.BoolVal() {
+ return n.Left // true || x => true
+ } else {
+ return n.Right // false || x => x
+ }
+ }
+ }
+ return n
+}
+
+// setTypeNode sets n to an OTYPE node representing t.
+func setTypeNode(n *Node, t *types.Type) {
+ n.Op = OTYPE
+ n.Type = t
+ n.Type.Nod = asTypesNode(n)
+}
+
+// getIotaValue returns the current value for "iota",
+// or -1 if not within a ConstSpec.
+func getIotaValue() int64 {
+ if i := len(typecheckdefstack); i > 0 {
+ if x := typecheckdefstack[i-1]; x.Op == OLITERAL {
+ return x.Iota()
+ }
+ }
+
+ if Curfn != nil && Curfn.Iota() >= 0 {
+ return Curfn.Iota()
+ }
+
+ return -1
+}
+
+// curpkg returns the current package, based on Curfn.
+func curpkg() *types.Pkg {
+ fn := Curfn
+ if fn == nil {
+ // Initialization expressions for package-scope variables.
+ return localpkg
+ }
+
+ // TODO(mdempsky): Standardize on either ODCLFUNC or ONAME for
+ // Curfn, rather than mixing them.
+ if fn.Op == ODCLFUNC {
+ fn = fn.Func.Nname
+ }
+
+ return fnpkg(fn)
+}
diff --git a/src/cmd/compile/internal/gc/types.go b/src/cmd/compile/internal/gc/types.go
new file mode 100644
index 0000000..748f845
--- /dev/null
+++ b/src/cmd/compile/internal/gc/types.go
@@ -0,0 +1,58 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+)
+
+// convenience constants
+const (
+ Txxx = types.Txxx
+
+ TINT8 = types.TINT8
+ TUINT8 = types.TUINT8
+ TINT16 = types.TINT16
+ TUINT16 = types.TUINT16
+ TINT32 = types.TINT32
+ TUINT32 = types.TUINT32
+ TINT64 = types.TINT64
+ TUINT64 = types.TUINT64
+ TINT = types.TINT
+ TUINT = types.TUINT
+ TUINTPTR = types.TUINTPTR
+
+ TCOMPLEX64 = types.TCOMPLEX64
+ TCOMPLEX128 = types.TCOMPLEX128
+
+ TFLOAT32 = types.TFLOAT32
+ TFLOAT64 = types.TFLOAT64
+
+ TBOOL = types.TBOOL
+
+ TPTR = types.TPTR
+ TFUNC = types.TFUNC
+ TSLICE = types.TSLICE
+ TARRAY = types.TARRAY
+ TSTRUCT = types.TSTRUCT
+ TCHAN = types.TCHAN
+ TMAP = types.TMAP
+ TINTER = types.TINTER
+ TFORW = types.TFORW
+ TANY = types.TANY
+ TSTRING = types.TSTRING
+ TUNSAFEPTR = types.TUNSAFEPTR
+
+ // pseudo-types for literals
+ TIDEAL = types.TIDEAL
+ TNIL = types.TNIL
+ TBLANK = types.TBLANK
+
+ // pseudo-types for frame layout
+ TFUNCARGS = types.TFUNCARGS
+ TCHANARGS = types.TCHANARGS
+
+ NTYPE = types.NTYPE
+)
diff --git a/src/cmd/compile/internal/gc/types_acc.go b/src/cmd/compile/internal/gc/types_acc.go
new file mode 100644
index 0000000..7240f72
--- /dev/null
+++ b/src/cmd/compile/internal/gc/types_acc.go
@@ -0,0 +1,16 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements convertions between *types.Node and *Node.
+// TODO(gri) try to eliminate these soon
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "unsafe"
+)
+
+func asNode(n *types.Node) *Node { return (*Node)(unsafe.Pointer(n)) }
+func asTypesNode(n *Node) *types.Node { return (*types.Node)(unsafe.Pointer(n)) }
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
new file mode 100644
index 0000000..ff8cabd
--- /dev/null
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -0,0 +1,453 @@
+// Copyright 2009 The Go 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(gri) This file should probably become part of package types.
+
+package gc
+
+import "cmd/compile/internal/types"
+
+// builtinpkg is a fake package that declares the universe block.
+var builtinpkg *types.Pkg
+
+var basicTypes = [...]struct {
+ name string
+ etype types.EType
+}{
+ {"int8", TINT8},
+ {"int16", TINT16},
+ {"int32", TINT32},
+ {"int64", TINT64},
+ {"uint8", TUINT8},
+ {"uint16", TUINT16},
+ {"uint32", TUINT32},
+ {"uint64", TUINT64},
+ {"float32", TFLOAT32},
+ {"float64", TFLOAT64},
+ {"complex64", TCOMPLEX64},
+ {"complex128", TCOMPLEX128},
+ {"bool", TBOOL},
+ {"string", TSTRING},
+}
+
+var typedefs = [...]struct {
+ name string
+ etype types.EType
+ sameas32 types.EType
+ sameas64 types.EType
+}{
+ {"int", TINT, TINT32, TINT64},
+ {"uint", TUINT, TUINT32, TUINT64},
+ {"uintptr", TUINTPTR, TUINT32, TUINT64},
+}
+
+var builtinFuncs = [...]struct {
+ name string
+ op Op
+}{
+ {"append", OAPPEND},
+ {"cap", OCAP},
+ {"close", OCLOSE},
+ {"complex", OCOMPLEX},
+ {"copy", OCOPY},
+ {"delete", ODELETE},
+ {"imag", OIMAG},
+ {"len", OLEN},
+ {"make", OMAKE},
+ {"new", ONEW},
+ {"panic", OPANIC},
+ {"print", OPRINT},
+ {"println", OPRINTN},
+ {"real", OREAL},
+ {"recover", ORECOVER},
+}
+
+// isBuiltinFuncName reports whether name matches a builtin function
+// name.
+func isBuiltinFuncName(name string) bool {
+ for _, fn := range &builtinFuncs {
+ if fn.name == name {
+ return true
+ }
+ }
+ return false
+}
+
+var unsafeFuncs = [...]struct {
+ name string
+ op Op
+}{
+ {"Alignof", OALIGNOF},
+ {"Offsetof", OOFFSETOF},
+ {"Sizeof", OSIZEOF},
+}
+
+// initUniverse initializes the universe block.
+func initUniverse() {
+ lexinit()
+ typeinit()
+ lexinit1()
+}
+
+// lexinit initializes known symbols and the basic types.
+func lexinit() {
+ for _, s := range &basicTypes {
+ etype := s.etype
+ if int(etype) >= len(types.Types) {
+ Fatalf("lexinit: %s bad etype", s.name)
+ }
+ s2 := builtinpkg.Lookup(s.name)
+ t := types.Types[etype]
+ if t == nil {
+ t = types.New(etype)
+ t.Sym = s2
+ if etype != TANY && etype != TSTRING {
+ dowidth(t)
+ }
+ types.Types[etype] = t
+ }
+ s2.Def = asTypesNode(typenod(t))
+ asNode(s2.Def).Name = new(Name)
+ }
+
+ for _, s := range &builtinFuncs {
+ s2 := builtinpkg.Lookup(s.name)
+ s2.Def = asTypesNode(newname(s2))
+ asNode(s2.Def).SetSubOp(s.op)
+ }
+
+ for _, s := range &unsafeFuncs {
+ s2 := unsafepkg.Lookup(s.name)
+ s2.Def = asTypesNode(newname(s2))
+ asNode(s2.Def).SetSubOp(s.op)
+ }
+
+ types.UntypedString = types.New(TSTRING)
+ types.UntypedBool = types.New(TBOOL)
+ types.Types[TANY] = types.New(TANY)
+
+ s := builtinpkg.Lookup("true")
+ s.Def = asTypesNode(nodbool(true))
+ asNode(s.Def).Sym = lookup("true")
+ asNode(s.Def).Name = new(Name)
+ asNode(s.Def).Type = types.UntypedBool
+
+ s = builtinpkg.Lookup("false")
+ s.Def = asTypesNode(nodbool(false))
+ asNode(s.Def).Sym = lookup("false")
+ asNode(s.Def).Name = new(Name)
+ asNode(s.Def).Type = types.UntypedBool
+
+ s = lookup("_")
+ s.Block = -100
+ s.Def = asTypesNode(newname(s))
+ types.Types[TBLANK] = types.New(TBLANK)
+ asNode(s.Def).Type = types.Types[TBLANK]
+ nblank = asNode(s.Def)
+
+ s = builtinpkg.Lookup("_")
+ s.Block = -100
+ s.Def = asTypesNode(newname(s))
+ types.Types[TBLANK] = types.New(TBLANK)
+ asNode(s.Def).Type = types.Types[TBLANK]
+
+ types.Types[TNIL] = types.New(TNIL)
+ s = builtinpkg.Lookup("nil")
+ var v Val
+ v.U = new(NilVal)
+ s.Def = asTypesNode(nodlit(v))
+ asNode(s.Def).Sym = s
+ asNode(s.Def).Name = new(Name)
+
+ s = builtinpkg.Lookup("iota")
+ s.Def = asTypesNode(nod(OIOTA, nil, nil))
+ asNode(s.Def).Sym = s
+ asNode(s.Def).Name = new(Name)
+}
+
+func typeinit() {
+ if Widthptr == 0 {
+ Fatalf("typeinit before betypeinit")
+ }
+
+ for et := types.EType(0); et < NTYPE; et++ {
+ simtype[et] = et
+ }
+
+ types.Types[TPTR] = types.New(TPTR)
+ dowidth(types.Types[TPTR])
+
+ t := types.New(TUNSAFEPTR)
+ types.Types[TUNSAFEPTR] = t
+ t.Sym = unsafepkg.Lookup("Pointer")
+ t.Sym.Def = asTypesNode(typenod(t))
+ asNode(t.Sym.Def).Name = new(Name)
+ dowidth(types.Types[TUNSAFEPTR])
+
+ for et := TINT8; et <= TUINT64; et++ {
+ isInt[et] = true
+ }
+ isInt[TINT] = true
+ isInt[TUINT] = true
+ isInt[TUINTPTR] = true
+
+ isFloat[TFLOAT32] = true
+ isFloat[TFLOAT64] = true
+
+ isComplex[TCOMPLEX64] = true
+ isComplex[TCOMPLEX128] = true
+
+ // initialize okfor
+ for et := types.EType(0); et < NTYPE; et++ {
+ if isInt[et] || et == TIDEAL {
+ okforeq[et] = true
+ okforcmp[et] = true
+ okforarith[et] = true
+ okforadd[et] = true
+ okforand[et] = true
+ okforconst[et] = true
+ issimple[et] = true
+ minintval[et] = new(Mpint)
+ maxintval[et] = new(Mpint)
+ }
+
+ if isFloat[et] {
+ okforeq[et] = true
+ okforcmp[et] = true
+ okforadd[et] = true
+ okforarith[et] = true
+ okforconst[et] = true
+ issimple[et] = true
+ minfltval[et] = newMpflt()
+ maxfltval[et] = newMpflt()
+ }
+
+ if isComplex[et] {
+ okforeq[et] = true
+ okforadd[et] = true
+ okforarith[et] = true
+ okforconst[et] = true
+ issimple[et] = true
+ }
+ }
+
+ issimple[TBOOL] = true
+
+ okforadd[TSTRING] = true
+
+ okforbool[TBOOL] = true
+
+ okforcap[TARRAY] = true
+ okforcap[TCHAN] = true
+ okforcap[TSLICE] = true
+
+ okforconst[TBOOL] = true
+ okforconst[TSTRING] = true
+
+ okforlen[TARRAY] = true
+ okforlen[TCHAN] = true
+ okforlen[TMAP] = true
+ okforlen[TSLICE] = true
+ okforlen[TSTRING] = true
+
+ okforeq[TPTR] = true
+ okforeq[TUNSAFEPTR] = true
+ okforeq[TINTER] = true
+ okforeq[TCHAN] = true
+ okforeq[TSTRING] = true
+ okforeq[TBOOL] = true
+ okforeq[TMAP] = true // nil only; refined in typecheck
+ okforeq[TFUNC] = true // nil only; refined in typecheck
+ okforeq[TSLICE] = true // nil only; refined in typecheck
+ okforeq[TARRAY] = true // only if element type is comparable; refined in typecheck
+ okforeq[TSTRUCT] = true // only if all struct fields are comparable; refined in typecheck
+
+ okforcmp[TSTRING] = true
+
+ var i int
+ for i = 0; i < len(okfor); i++ {
+ okfor[i] = okfornone[:]
+ }
+
+ // binary
+ okfor[OADD] = okforadd[:]
+ okfor[OAND] = okforand[:]
+ okfor[OANDAND] = okforbool[:]
+ okfor[OANDNOT] = okforand[:]
+ okfor[ODIV] = okforarith[:]
+ okfor[OEQ] = okforeq[:]
+ okfor[OGE] = okforcmp[:]
+ okfor[OGT] = okforcmp[:]
+ okfor[OLE] = okforcmp[:]
+ okfor[OLT] = okforcmp[:]
+ okfor[OMOD] = okforand[:]
+ okfor[OMUL] = okforarith[:]
+ okfor[ONE] = okforeq[:]
+ okfor[OOR] = okforand[:]
+ okfor[OOROR] = okforbool[:]
+ okfor[OSUB] = okforarith[:]
+ okfor[OXOR] = okforand[:]
+ okfor[OLSH] = okforand[:]
+ okfor[ORSH] = okforand[:]
+
+ // unary
+ okfor[OBITNOT] = okforand[:]
+ okfor[ONEG] = okforarith[:]
+ okfor[ONOT] = okforbool[:]
+ okfor[OPLUS] = okforarith[:]
+
+ // special
+ okfor[OCAP] = okforcap[:]
+ okfor[OLEN] = okforlen[:]
+
+ // comparison
+ iscmp[OLT] = true
+ iscmp[OGT] = true
+ iscmp[OGE] = true
+ iscmp[OLE] = true
+ iscmp[OEQ] = true
+ iscmp[ONE] = true
+
+ maxintval[TINT8].SetString("0x7f")
+ minintval[TINT8].SetString("-0x80")
+ maxintval[TINT16].SetString("0x7fff")
+ minintval[TINT16].SetString("-0x8000")
+ maxintval[TINT32].SetString("0x7fffffff")
+ minintval[TINT32].SetString("-0x80000000")
+ maxintval[TINT64].SetString("0x7fffffffffffffff")
+ minintval[TINT64].SetString("-0x8000000000000000")
+
+ maxintval[TUINT8].SetString("0xff")
+ maxintval[TUINT16].SetString("0xffff")
+ maxintval[TUINT32].SetString("0xffffffff")
+ maxintval[TUINT64].SetString("0xffffffffffffffff")
+
+ // f is valid float if min < f < max. (min and max are not themselves valid.)
+ maxfltval[TFLOAT32].SetString("33554431p103") // 2^24-1 p (127-23) + 1/2 ulp
+ minfltval[TFLOAT32].SetString("-33554431p103")
+ maxfltval[TFLOAT64].SetString("18014398509481983p970") // 2^53-1 p (1023-52) + 1/2 ulp
+ minfltval[TFLOAT64].SetString("-18014398509481983p970")
+
+ maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32]
+ minfltval[TCOMPLEX64] = minfltval[TFLOAT32]
+ maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64]
+ minfltval[TCOMPLEX128] = minfltval[TFLOAT64]
+
+ types.Types[TINTER] = types.New(TINTER) // empty interface
+
+ // simple aliases
+ simtype[TMAP] = TPTR
+ simtype[TCHAN] = TPTR
+ simtype[TFUNC] = TPTR
+ simtype[TUNSAFEPTR] = TPTR
+
+ slicePtrOffset = 0
+ sliceLenOffset = Rnd(slicePtrOffset+int64(Widthptr), int64(Widthptr))
+ sliceCapOffset = Rnd(sliceLenOffset+int64(Widthptr), int64(Widthptr))
+ sizeofSlice = Rnd(sliceCapOffset+int64(Widthptr), int64(Widthptr))
+
+ // string is same as slice wo the cap
+ sizeofString = Rnd(sliceLenOffset+int64(Widthptr), int64(Widthptr))
+
+ dowidth(types.Types[TSTRING])
+ dowidth(types.UntypedString)
+}
+
+func makeErrorInterface() *types.Type {
+ field := types.NewField()
+ field.Type = types.Types[TSTRING]
+ f := functypefield(fakeRecvField(), nil, []*types.Field{field})
+
+ field = types.NewField()
+ field.Sym = lookup("Error")
+ field.Type = f
+
+ t := types.New(TINTER)
+ t.SetInterface([]*types.Field{field})
+ return t
+}
+
+func lexinit1() {
+ // error type
+ s := builtinpkg.Lookup("error")
+ types.Errortype = makeErrorInterface()
+ types.Errortype.Sym = s
+ types.Errortype.Orig = makeErrorInterface()
+ s.Def = asTypesNode(typenod(types.Errortype))
+ dowidth(types.Errortype)
+
+ // We create separate byte and rune types for better error messages
+ // rather than just creating type alias *types.Sym's for the uint8 and
+ // int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
+ // TODO(gri) Should we get rid of this special case (at the cost
+ // of less informative error messages involving bytes and runes)?
+ // (Alternatively, we could introduce an OTALIAS node representing
+ // type aliases, albeit at the cost of having to deal with it everywhere).
+
+ // byte alias
+ s = builtinpkg.Lookup("byte")
+ types.Bytetype = types.New(TUINT8)
+ types.Bytetype.Sym = s
+ s.Def = asTypesNode(typenod(types.Bytetype))
+ asNode(s.Def).Name = new(Name)
+ dowidth(types.Bytetype)
+
+ // rune alias
+ s = builtinpkg.Lookup("rune")
+ types.Runetype = types.New(TINT32)
+ types.Runetype.Sym = s
+ s.Def = asTypesNode(typenod(types.Runetype))
+ asNode(s.Def).Name = new(Name)
+ dowidth(types.Runetype)
+
+ // backend-dependent builtin types (e.g. int).
+ for _, s := range &typedefs {
+ s1 := builtinpkg.Lookup(s.name)
+
+ sameas := s.sameas32
+ if Widthptr == 8 {
+ sameas = s.sameas64
+ }
+
+ simtype[s.etype] = sameas
+ minfltval[s.etype] = minfltval[sameas]
+ maxfltval[s.etype] = maxfltval[sameas]
+ minintval[s.etype] = minintval[sameas]
+ maxintval[s.etype] = maxintval[sameas]
+
+ t := types.New(s.etype)
+ t.Sym = s1
+ types.Types[s.etype] = t
+ s1.Def = asTypesNode(typenod(t))
+ asNode(s1.Def).Name = new(Name)
+ s1.Origpkg = builtinpkg
+
+ dowidth(t)
+ }
+}
+
+// finishUniverse makes the universe block visible within the current package.
+func finishUniverse() {
+ // Operationally, this is similar to a dot import of builtinpkg, except
+ // that we silently skip symbols that are already declared in the
+ // package block rather than emitting a redeclared symbol error.
+
+ for _, s := range builtinpkg.Syms {
+ if s.Def == nil {
+ continue
+ }
+ s1 := lookup(s.Name)
+ if s1.Def != nil {
+ continue
+ }
+
+ s1.Def = s.Def
+ s1.Block = s.Block
+ }
+
+ nodfp = newname(lookup(".fp"))
+ nodfp.Type = types.Types[TINT32]
+ nodfp.SetClass(PPARAM)
+ nodfp.Name.SetUsed(true)
+}
diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go
new file mode 100644
index 0000000..2233961
--- /dev/null
+++ b/src/cmd/compile/internal/gc/unsafe.go
@@ -0,0 +1,76 @@
+// Copyright 2009 The Go Authors. 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
+
+// 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, ctxExpr)
+ n.Left = defaultlit(n.Left, nil)
+ tr := n.Left.Type
+ if tr == nil {
+ return 0
+ }
+ dowidth(tr)
+ if n.Op == OALIGNOF {
+ return int64(tr.Align)
+ }
+ return tr.Width
+
+ case OOFFSETOF:
+ // must be a selector.
+ 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.
+ n.Left.Left = typecheck(n.Left.Left, ctxExpr)
+ base := n.Left.Left
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ if n.Left.Type == nil {
+ return 0
+ }
+ switch n.Left.Op {
+ case ODOT, ODOTPTR:
+ break
+ case OCALLPART:
+ yyerror("invalid expression %v: argument is a method value", n)
+ return 0
+ default:
+ yyerror("invalid expression %v", n)
+ return 0
+ }
+
+ // Sum offsets for dots until we reach base.
+ 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 r.Left != base {
+ yyerror("invalid expression %v: selector implies indirection of embedded %v", n, r.Left)
+ return 0
+ }
+ fallthrough
+ case ODOT:
+ v += r.Xoffset
+ default:
+ Dump("unsafenmagic", n.Left)
+ Fatalf("impossible %#v node after dot insertion", r.Op)
+ }
+ }
+ return v
+ }
+
+ 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
new file mode 100644
index 0000000..58be2f8
--- /dev/null
+++ b/src/cmd/compile/internal/gc/util.go
@@ -0,0 +1,103 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "os"
+ "runtime"
+ "runtime/pprof"
+)
+
+// Line returns n's position as a string. If n has been inlined,
+// it uses the outermost position where n has been inlined.
+func (n *Node) Line() string {
+ return linestr(n.Pos)
+}
+
+var atExitFuncs []func()
+
+func atExit(f func()) {
+ atExitFuncs = append(atExitFuncs, f)
+}
+
+func Exit(code int) {
+ for i := len(atExitFuncs) - 1; i >= 0; i-- {
+ f := atExitFuncs[i]
+ atExitFuncs = atExitFuncs[:i]
+ f()
+ }
+ os.Exit(code)
+}
+
+var (
+ blockprofile string
+ cpuprofile string
+ memprofile string
+ memprofilerate int64
+ traceprofile string
+ traceHandler func(string)
+ mutexprofile string
+)
+
+func startProfile() {
+ if cpuprofile != "" {
+ f, err := os.Create(cpuprofile)
+ if err != nil {
+ Fatalf("%v", err)
+ }
+ if err := pprof.StartCPUProfile(f); err != nil {
+ Fatalf("%v", err)
+ }
+ atExit(pprof.StopCPUProfile)
+ }
+ if memprofile != "" {
+ if memprofilerate != 0 {
+ runtime.MemProfileRate = int(memprofilerate)
+ }
+ f, err := os.Create(memprofile)
+ if err != nil {
+ Fatalf("%v", err)
+ }
+ atExit(func() {
+ // Profile all outstanding allocations.
+ runtime.GC()
+ // compilebench parses the memory profile to extract memstats,
+ // which are only written in the legacy pprof format.
+ // See golang.org/issue/18641 and runtime/pprof/pprof.go:writeHeap.
+ const writeLegacyFormat = 1
+ if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
+ Fatalf("%v", err)
+ }
+ })
+ } else {
+ // Not doing memory profiling; disable it entirely.
+ runtime.MemProfileRate = 0
+ }
+ if blockprofile != "" {
+ f, err := os.Create(blockprofile)
+ if err != nil {
+ Fatalf("%v", err)
+ }
+ runtime.SetBlockProfileRate(1)
+ atExit(func() {
+ pprof.Lookup("block").WriteTo(f, 0)
+ f.Close()
+ })
+ }
+ if mutexprofile != "" {
+ f, err := os.Create(mutexprofile)
+ if err != nil {
+ Fatalf("%v", err)
+ }
+ startMutexProfiling()
+ atExit(func() {
+ pprof.Lookup("mutex").WriteTo(f, 0)
+ f.Close()
+ })
+ }
+ if traceprofile != "" && traceHandler != nil {
+ traceHandler(traceprofile)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
new file mode 100644
index 0000000..02a7269
--- /dev/null
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -0,0 +1,4125 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/objabi"
+ "cmd/internal/sys"
+ "encoding/binary"
+ "fmt"
+ "strings"
+)
+
+// The constant is known to runtime.
+const tmpstringbufsize = 32
+const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
+
+func walk(fn *Node) {
+ Curfn = fn
+
+ if Debug.W != 0 {
+ s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym)
+ dumplist(s, Curfn.Nbody)
+ }
+
+ lno := lineno
+
+ // Final typecheck for any unused variables.
+ for i, ln := range fn.Func.Dcl {
+ if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) {
+ ln = typecheck(ln, ctxExpr|ctxAssign)
+ fn.Func.Dcl[i] = ln
+ }
+ }
+
+ // Propagate the used flag for typeswitch variables up to the NONAME in its definition.
+ for _, ln := range fn.Func.Dcl {
+ if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Name.Used() {
+ ln.Name.Defn.Left.Name.SetUsed(true)
+ }
+ }
+
+ for _, ln := range fn.Func.Dcl {
+ if ln.Op != ONAME || (ln.Class() != PAUTO && ln.Class() != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Name.Used() {
+ continue
+ }
+ if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
+ if defn.Left.Name.Used() {
+ continue
+ }
+ yyerrorl(defn.Left.Pos, "%v declared but not used", ln.Sym)
+ defn.Left.Name.SetUsed(true) // suppress repeats
+ } else {
+ yyerrorl(ln.Pos, "%v declared but not used", ln.Sym)
+ }
+ }
+
+ lineno = lno
+ if nerrors != 0 {
+ return
+ }
+ walkstmtlist(Curfn.Nbody.Slice())
+ if Debug.W != 0 {
+ s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
+ dumplist(s, Curfn.Nbody)
+ }
+
+ zeroResults()
+ heapmoves()
+ if Debug.W != 0 && Curfn.Func.Enter.Len() > 0 {
+ s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
+ dumplist(s, Curfn.Func.Enter)
+ }
+}
+
+func walkstmtlist(s []*Node) {
+ for i := range s {
+ s[i] = walkstmt(s[i])
+ }
+}
+
+func paramoutheap(fn *Node) bool {
+ for _, ln := range fn.Func.Dcl {
+ switch ln.Class() {
+ case PPARAMOUT:
+ if ln.isParamStackCopy() || ln.Name.Addrtaken() {
+ return true
+ }
+
+ case PAUTO:
+ // stop early - parameters are over
+ return false
+ }
+ }
+
+ return false
+}
+
+// The result of walkstmt MUST be assigned back to n, e.g.
+// n.Left = walkstmt(n.Left)
+func walkstmt(n *Node) *Node {
+ if n == nil {
+ return n
+ }
+
+ setlineno(n)
+
+ walkstmtlist(n.Ninit.Slice())
+
+ switch n.Op {
+ default:
+ if n.Op == ONAME {
+ yyerror("%v is not a top level statement", n.Sym)
+ } else {
+ yyerror("%v is not a top level statement", n.Op)
+ }
+ Dump("nottop", n)
+
+ case OAS,
+ OASOP,
+ OAS2,
+ OAS2DOTTYPE,
+ OAS2RECV,
+ OAS2FUNC,
+ OAS2MAPR,
+ OCLOSE,
+ OCOPY,
+ OCALLMETH,
+ OCALLINTER,
+ OCALL,
+ OCALLFUNC,
+ ODELETE,
+ OSEND,
+ OPRINT,
+ OPRINTN,
+ OPANIC,
+ OEMPTY,
+ ORECOVER,
+ OGETG:
+ if n.Typecheck() == 0 {
+ Fatalf("missing typecheck: %+v", n)
+ }
+ wascopy := n.Op == OCOPY
+ init := n.Ninit
+ n.Ninit.Set(nil)
+ n = walkexpr(n, &init)
+ n = addinit(n, init.Slice())
+ if wascopy && n.Op == OCONVNOP {
+ n.Op = OEMPTY // don't leave plain values as statements.
+ }
+
+ // special case for a receive where we throw away
+ // the value received.
+ case ORECV:
+ if n.Typecheck() == 0 {
+ Fatalf("missing typecheck: %+v", n)
+ }
+ init := n.Ninit
+ n.Ninit.Set(nil)
+
+ n.Left = walkexpr(n.Left, &init)
+ n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, n.Left, nodnil())
+ n = walkexpr(n, &init)
+
+ n = addinit(n, init.Slice())
+
+ case OBREAK,
+ OCONTINUE,
+ OFALL,
+ OGOTO,
+ OLABEL,
+ ODCLCONST,
+ ODCLTYPE,
+ OCHECKNIL,
+ OVARDEF,
+ OVARKILL,
+ OVARLIVE:
+ break
+
+ case ODCL:
+ v := n.Left
+ if v.Class() == PAUTOHEAP {
+ if compiling_runtime {
+ yyerror("%v escapes to heap, not allowed in runtime", v)
+ }
+ if prealloc[v] == nil {
+ prealloc[v] = callnew(v.Type)
+ }
+ nn := nod(OAS, v.Name.Param.Heapaddr, prealloc[v])
+ nn.SetColas(true)
+ nn = typecheck(nn, ctxStmt)
+ return walkstmt(nn)
+ }
+
+ case OBLOCK:
+ walkstmtlist(n.List.Slice())
+
+ case OCASE:
+ yyerror("case statement out of place")
+
+ case ODEFER:
+ Curfn.Func.SetHasDefer(true)
+ Curfn.Func.numDefers++
+ if Curfn.Func.numDefers > maxOpenDefers {
+ // Don't allow open-coded defers if there are more than
+ // 8 defers in the function, since we use a single
+ // byte to record active defers.
+ Curfn.Func.SetOpenCodedDeferDisallowed(true)
+ }
+ if n.Esc != EscNever {
+ // If n.Esc is not EscNever, then this defer occurs in a loop,
+ // so open-coded defers cannot be used in this function.
+ Curfn.Func.SetOpenCodedDeferDisallowed(true)
+ }
+ fallthrough
+ case OGO:
+ switch n.Left.Op {
+ case OPRINT, OPRINTN:
+ n.Left = wrapCall(n.Left, &n.Ninit)
+
+ case ODELETE:
+ if mapfast(n.Left.List.First().Type) == mapslow {
+ n.Left = wrapCall(n.Left, &n.Ninit)
+ } else {
+ n.Left = walkexpr(n.Left, &n.Ninit)
+ }
+
+ case OCOPY:
+ n.Left = copyany(n.Left, &n.Ninit, true)
+
+ case OCALLFUNC, OCALLMETH, OCALLINTER:
+ if n.Left.Nbody.Len() > 0 {
+ n.Left = wrapCall(n.Left, &n.Ninit)
+ } else {
+ n.Left = walkexpr(n.Left, &n.Ninit)
+ }
+
+ default:
+ n.Left = walkexpr(n.Left, &n.Ninit)
+ }
+
+ case OFOR, OFORUNTIL:
+ if n.Left != nil {
+ walkstmtlist(n.Left.Ninit.Slice())
+ init := n.Left.Ninit
+ n.Left.Ninit.Set(nil)
+ n.Left = walkexpr(n.Left, &init)
+ n.Left = addinit(n.Left, init.Slice())
+ }
+
+ n.Right = walkstmt(n.Right)
+ if n.Op == OFORUNTIL {
+ walkstmtlist(n.List.Slice())
+ }
+ walkstmtlist(n.Nbody.Slice())
+
+ case OIF:
+ n.Left = walkexpr(n.Left, &n.Ninit)
+ walkstmtlist(n.Nbody.Slice())
+ walkstmtlist(n.Rlist.Slice())
+
+ case ORETURN:
+ Curfn.Func.numReturns++
+ if n.List.Len() == 0 {
+ break
+ }
+ if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) || Curfn.Func.HasDefer() {
+ // assign to the function out parameters,
+ // so that reorder3 can fix up conflicts
+ var rl []*Node
+
+ for _, ln := range Curfn.Func.Dcl {
+ cl := ln.Class()
+ if cl == PAUTO || cl == PAUTOHEAP {
+ break
+ }
+ if cl == PPARAMOUT {
+ if ln.isParamStackCopy() {
+ ln = walkexpr(typecheck(nod(ODEREF, ln.Name.Param.Heapaddr, nil), ctxExpr), nil)
+ }
+ rl = append(rl, ln)
+ }
+ }
+
+ if got, want := n.List.Len(), len(rl); got != want {
+ // order should have rewritten multi-value function calls
+ // with explicit OAS2FUNC nodes.
+ Fatalf("expected %v return arguments, have %v", want, got)
+ }
+
+ // move function calls out, to make reorder3's job easier.
+ walkexprlistsafe(n.List.Slice(), &n.Ninit)
+
+ ll := ascompatee(n.Op, rl, n.List.Slice(), &n.Ninit)
+ n.List.Set(reorder3(ll))
+ break
+ }
+ walkexprlist(n.List.Slice(), &n.Ninit)
+
+ // For each return parameter (lhs), assign the corresponding result (rhs).
+ lhs := Curfn.Type.Results()
+ rhs := n.List.Slice()
+ res := make([]*Node, lhs.NumFields())
+ for i, nl := range lhs.FieldSlice() {
+ nname := asNode(nl.Nname)
+ if nname.isParamHeapCopy() {
+ nname = nname.Name.Param.Stackcopy
+ }
+ a := nod(OAS, nname, rhs[i])
+ res[i] = convas(a, &n.Ninit)
+ }
+ n.List.Set(res)
+
+ case ORETJMP:
+ break
+
+ case OINLMARK:
+ break
+
+ case OSELECT:
+ walkselect(n)
+
+ case OSWITCH:
+ walkswitch(n)
+
+ case ORANGE:
+ n = walkrange(n)
+ }
+
+ if n.Op == ONAME {
+ Fatalf("walkstmt ended up with name: %+v", n)
+ }
+ return n
+}
+
+// walk the whole tree of the body of an
+// expression or simple statement.
+// the types expressions are calculated.
+// compile-time constants are evaluated.
+// complex side effects like statements are appended to init
+func walkexprlist(s []*Node, init *Nodes) {
+ for i := range s {
+ s[i] = walkexpr(s[i], init)
+ }
+}
+
+func walkexprlistsafe(s []*Node, init *Nodes) {
+ for i, n := range s {
+ s[i] = safeexpr(n, init)
+ s[i] = walkexpr(s[i], init)
+ }
+}
+
+func walkexprlistcheap(s []*Node, init *Nodes) {
+ for i, n := range s {
+ s[i] = cheapexpr(n, init)
+ s[i] = walkexpr(s[i], init)
+ }
+}
+
+// convFuncName builds the runtime function name for interface conversion.
+// It also reports whether the function expects the data by address.
+// Not all names are possible. For example, we never generate convE2E or convE2I.
+func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) {
+ tkind := to.Tie()
+ switch from.Tie() {
+ case 'I':
+ if tkind == 'I' {
+ return "convI2I", false
+ }
+ case 'T':
+ switch {
+ case from.Size() == 2 && from.Align == 2:
+ return "convT16", false
+ case from.Size() == 4 && from.Align == 4 && !from.HasPointers():
+ return "convT32", false
+ case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !from.HasPointers():
+ return "convT64", false
+ }
+ if sc := from.SoleComponent(); sc != nil {
+ switch {
+ case sc.IsString():
+ return "convTstring", false
+ case sc.IsSlice():
+ return "convTslice", false
+ }
+ }
+
+ switch tkind {
+ case 'E':
+ if !from.HasPointers() {
+ return "convT2Enoptr", true
+ }
+ return "convT2E", true
+ case 'I':
+ if !from.HasPointers() {
+ return "convT2Inoptr", true
+ }
+ return "convT2I", true
+ }
+ }
+ Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie())
+ panic("unreachable")
+}
+
+// The result of walkexpr MUST be assigned back to n, e.g.
+// n.Left = walkexpr(n.Left, init)
+func walkexpr(n *Node, init *Nodes) *Node {
+ if n == nil {
+ return n
+ }
+
+ // Eagerly checkwidth all expressions for the back end.
+ if n.Type != nil && !n.Type.WidthCalculated() {
+ switch n.Type.Etype {
+ case TBLANK, TNIL, TIDEAL:
+ default:
+ checkwidth(n.Type)
+ }
+ }
+
+ if init == &n.Ninit {
+ // not okay to use n->ninit when walking n,
+ // because we might replace n with some other node
+ // and would lose the init list.
+ Fatalf("walkexpr init == &n->ninit")
+ }
+
+ if n.Ninit.Len() != 0 {
+ walkstmtlist(n.Ninit.Slice())
+ init.AppendNodes(&n.Ninit)
+ }
+
+ lno := setlineno(n)
+
+ if Debug.w > 1 {
+ Dump("before walk expr", n)
+ }
+
+ if n.Typecheck() != 1 {
+ Fatalf("missed typecheck: %+v", n)
+ }
+
+ if n.Type.IsUntyped() {
+ Fatalf("expression has untyped type: %+v", n)
+ }
+
+ if n.Op == ONAME && n.Class() == PAUTOHEAP {
+ nn := nod(ODEREF, n.Name.Param.Heapaddr, nil)
+ nn = typecheck(nn, ctxExpr)
+ nn = walkexpr(nn, init)
+ nn.Left.MarkNonNil()
+ return nn
+ }
+
+opswitch:
+ switch n.Op {
+ default:
+ Dump("walk", n)
+ Fatalf("walkexpr: switch 1 unknown op %+S", n)
+
+ case ONONAME, OEMPTY, OGETG, ONEWOBJ:
+
+ case OTYPE, ONAME, OLITERAL:
+ // TODO(mdempsky): Just return n; see discussion on CL 38655.
+ // Perhaps refactor to use Node.mayBeShared for these instead.
+ // If these return early, make sure to still call
+ // stringsym for constant strings.
+
+ case ONOT, ONEG, OPLUS, OBITNOT, OREAL, OIMAG, ODOTMETH, ODOTINTER,
+ ODEREF, OSPTR, OITAB, OIDATA, OADDR:
+ n.Left = walkexpr(n.Left, init)
+
+ case OEFACE, OAND, OANDNOT, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH:
+ n.Left = walkexpr(n.Left, init)
+ n.Right = walkexpr(n.Right, init)
+
+ case ODOT, ODOTPTR:
+ usefield(n)
+ n.Left = walkexpr(n.Left, init)
+
+ case ODOTTYPE, ODOTTYPE2:
+ n.Left = walkexpr(n.Left, init)
+ // Set up interface type addresses for back end.
+ n.Right = typename(n.Type)
+ if n.Op == ODOTTYPE {
+ n.Right.Right = typename(n.Left.Type)
+ }
+ if !n.Type.IsInterface() && !n.Left.Type.IsEmptyInterface() {
+ n.List.Set1(itabname(n.Type, n.Left.Type))
+ }
+
+ case OLEN, OCAP:
+ if isRuneCount(n) {
+ // Replace len([]rune(string)) with runtime.countrunes(string).
+ n = mkcall("countrunes", n.Type, init, conv(n.Left.Left, types.Types[TSTRING]))
+ break
+ }
+
+ n.Left = walkexpr(n.Left, init)
+
+ // replace len(*[10]int) with 10.
+ // delayed until now to preserve side effects.
+ t := n.Left.Type
+
+ if t.IsPtr() {
+ t = t.Elem()
+ }
+ if t.IsArray() {
+ safeexpr(n.Left, init)
+ setintconst(n, t.NumElem())
+ n.SetTypecheck(1)
+ }
+
+ case OCOMPLEX:
+ // Use results from call expression as arguments for complex.
+ if n.Left == nil && n.Right == nil {
+ n.Left = n.List.First()
+ n.Right = n.List.Second()
+ }
+ n.Left = walkexpr(n.Left, init)
+ n.Right = walkexpr(n.Right, init)
+
+ case OEQ, ONE, OLT, OLE, OGT, OGE:
+ n = walkcompare(n, init)
+
+ case OANDAND, OOROR:
+ n.Left = walkexpr(n.Left, init)
+
+ // cannot put side effects from n.Right on init,
+ // because they cannot run before n.Left is checked.
+ // save elsewhere and store on the eventual n.Right.
+ var ll Nodes
+
+ n.Right = walkexpr(n.Right, &ll)
+ n.Right = addinit(n.Right, ll.Slice())
+
+ case OPRINT, OPRINTN:
+ n = walkprint(n, init)
+
+ case OPANIC:
+ n = mkcall("gopanic", nil, init, n.Left)
+
+ case ORECOVER:
+ n = mkcall("gorecover", n.Type, init, nod(OADDR, nodfp, nil))
+
+ case OCLOSUREVAR, OCFUNC:
+
+ case OCALLINTER, OCALLFUNC, OCALLMETH:
+ if n.Op == OCALLINTER || n.Op == OCALLMETH {
+ // We expect both interface call reflect.Type.Method and concrete
+ // call reflect.(*rtype).Method.
+ usemethod(n)
+ }
+ if n.Op == OCALLINTER {
+ markUsedIfaceMethod(n)
+ }
+
+ if n.Op == OCALLFUNC && n.Left.Op == OCLOSURE {
+ // Transform direct call of a closure to call of a normal function.
+ // transformclosure already did all preparation work.
+
+ // Prepend captured variables to argument list.
+ n.List.Prepend(n.Left.Func.Enter.Slice()...)
+
+ n.Left.Func.Enter.Set(nil)
+
+ // Replace OCLOSURE with ONAME/PFUNC.
+ n.Left = n.Left.Func.Closure.Func.Nname
+
+ // Update type of OCALLFUNC node.
+ // Output arguments had not changed, but their offsets could.
+ if n.Left.Type.NumResults() == 1 {
+ n.Type = n.Left.Type.Results().Field(0).Type
+ } else {
+ n.Type = n.Left.Type.Results()
+ }
+ }
+
+ walkCall(n, init)
+
+ case OAS, OASOP:
+ init.AppendNodes(&n.Ninit)
+
+ // Recognize m[k] = append(m[k], ...) so we can reuse
+ // the mapassign call.
+ mapAppend := n.Left.Op == OINDEXMAP && n.Right.Op == OAPPEND
+ if mapAppend && !samesafeexpr(n.Left, n.Right.List.First()) {
+ Fatalf("not same expressions: %v != %v", n.Left, n.Right.List.First())
+ }
+
+ n.Left = walkexpr(n.Left, init)
+ n.Left = safeexpr(n.Left, init)
+
+ if mapAppend {
+ n.Right.List.SetFirst(n.Left)
+ }
+
+ if n.Op == OASOP {
+ // Rewrite x op= y into x = x op y.
+ n.Right = nod(n.SubOp(), n.Left, n.Right)
+ n.Right = typecheck(n.Right, ctxExpr)
+
+ n.Op = OAS
+ n.ResetAux()
+ }
+
+ if oaslit(n, init) {
+ break
+ }
+
+ if n.Right == nil {
+ // TODO(austin): Check all "implicit zeroing"
+ break
+ }
+
+ if !instrumenting && isZero(n.Right) {
+ break
+ }
+
+ switch n.Right.Op {
+ default:
+ n.Right = walkexpr(n.Right, init)
+
+ case ORECV:
+ // x = <-c; n.Left is x, n.Right.Left is c.
+ // order.stmt made sure x is addressable.
+ n.Right.Left = walkexpr(n.Right.Left, init)
+
+ n1 := nod(OADDR, n.Left, nil)
+ r := n.Right.Left // the channel
+ n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, r, n1)
+ n = walkexpr(n, init)
+ break opswitch
+
+ case OAPPEND:
+ // x = append(...)
+ r := n.Right
+ if r.Type.Elem().NotInHeap() {
+ yyerror("%v can't be allocated in Go; it is incomplete (or unallocatable)", r.Type.Elem())
+ }
+ switch {
+ case isAppendOfMake(r):
+ // x = append(y, make([]T, y)...)
+ r = extendslice(r, init)
+ case r.IsDDD():
+ r = appendslice(r, init) // also works for append(slice, string).
+ default:
+ r = walkappend(r, init, n)
+ }
+ n.Right = r
+ if r.Op == OAPPEND {
+ // Left in place for back end.
+ // Do not add a new write barrier.
+ // Set up address of type for back end.
+ r.Left = typename(r.Type.Elem())
+ break opswitch
+ }
+ // Otherwise, lowered for race detector.
+ // Treat as ordinary assignment.
+ }
+
+ if n.Left != nil && n.Right != nil {
+ n = convas(n, init)
+ }
+
+ case OAS2:
+ init.AppendNodes(&n.Ninit)
+ walkexprlistsafe(n.List.Slice(), init)
+ walkexprlistsafe(n.Rlist.Slice(), init)
+ ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
+ ll = reorder3(ll)
+ n = liststmt(ll)
+
+ // a,b,... = fn()
+ case OAS2FUNC:
+ init.AppendNodes(&n.Ninit)
+
+ r := n.Right
+ walkexprlistsafe(n.List.Slice(), init)
+ r = walkexpr(r, init)
+
+ if isIntrinsicCall(r) {
+ n.Right = r
+ break
+ }
+ init.Append(r)
+
+ ll := ascompatet(n.List, r.Type)
+ n = liststmt(ll)
+
+ // x, y = <-c
+ // order.stmt made sure x is addressable or blank.
+ case OAS2RECV:
+ init.AppendNodes(&n.Ninit)
+
+ r := n.Right
+ walkexprlistsafe(n.List.Slice(), init)
+ r.Left = walkexpr(r.Left, init)
+ var n1 *Node
+ if n.List.First().isBlank() {
+ n1 = nodnil()
+ } else {
+ n1 = nod(OADDR, n.List.First(), nil)
+ }
+ fn := chanfn("chanrecv2", 2, r.Left.Type)
+ ok := n.List.Second()
+ call := mkcall1(fn, types.Types[TBOOL], init, r.Left, n1)
+ n = nod(OAS, ok, call)
+ n = typecheck(n, ctxStmt)
+
+ // a,b = m[i]
+ case OAS2MAPR:
+ init.AppendNodes(&n.Ninit)
+
+ r := n.Right
+ walkexprlistsafe(n.List.Slice(), init)
+ r.Left = walkexpr(r.Left, init)
+ r.Right = walkexpr(r.Right, init)
+ t := r.Left.Type
+
+ fast := mapfast(t)
+ var key *Node
+ if fast != mapslow {
+ // fast versions take key by value
+ key = r.Right
+ } else {
+ // standard version takes key by reference
+ // order.expr made sure key is addressable.
+ key = nod(OADDR, r.Right, nil)
+ }
+
+ // from:
+ // a,b = m[i]
+ // to:
+ // var,b = mapaccess2*(t, m, i)
+ // a = *var
+ a := n.List.First()
+
+ if w := t.Elem().Width; w <= zeroValSize {
+ fn := mapfn(mapaccess2[fast], t)
+ r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
+ } else {
+ fn := mapfn("mapaccess2_fat", t)
+ z := zeroaddr(w)
+ r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key, z)
+ }
+
+ // mapaccess2* returns a typed bool, but due to spec changes,
+ // the boolean result of i.(T) is now untyped so we make it the
+ // same type as the variable on the lhs.
+ if ok := n.List.Second(); !ok.isBlank() && ok.Type.IsBoolean() {
+ r.Type.Field(1).Type = ok.Type
+ }
+ n.Right = r
+ n.Op = OAS2FUNC
+
+ // don't generate a = *var if a is _
+ if !a.isBlank() {
+ var_ := temp(types.NewPtr(t.Elem()))
+ var_.SetTypecheck(1)
+ var_.MarkNonNil() // mapaccess always returns a non-nil pointer
+ n.List.SetFirst(var_)
+ n = walkexpr(n, init)
+ init.Append(n)
+ n = nod(OAS, a, nod(ODEREF, var_, nil))
+ }
+
+ n = typecheck(n, ctxStmt)
+ n = walkexpr(n, init)
+
+ case ODELETE:
+ init.AppendNodes(&n.Ninit)
+ map_ := n.List.First()
+ key := n.List.Second()
+ map_ = walkexpr(map_, init)
+ key = walkexpr(key, init)
+
+ t := map_.Type
+ fast := mapfast(t)
+ if fast == mapslow {
+ // order.stmt made sure key is addressable.
+ key = nod(OADDR, key, nil)
+ }
+ n = mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
+
+ case OAS2DOTTYPE:
+ walkexprlistsafe(n.List.Slice(), init)
+ n.Right = walkexpr(n.Right, init)
+
+ case OCONVIFACE:
+ n.Left = walkexpr(n.Left, init)
+
+ fromType := n.Left.Type
+ toType := n.Type
+
+ if !fromType.IsInterface() && !Curfn.Func.Nname.isBlank() { // skip unnamed functions (func _())
+ markTypeUsedInInterface(fromType, Curfn.Func.lsym)
+ }
+
+ // typeword generates the type word of the interface value.
+ typeword := func() *Node {
+ if toType.IsEmptyInterface() {
+ return typename(fromType)
+ }
+ return itabname(fromType, toType)
+ }
+
+ // Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
+ if isdirectiface(fromType) {
+ l := nod(OEFACE, typeword(), n.Left)
+ l.Type = toType
+ l.SetTypecheck(n.Typecheck())
+ n = l
+ break
+ }
+
+ if staticuint64s == nil {
+ staticuint64s = newname(Runtimepkg.Lookup("staticuint64s"))
+ staticuint64s.SetClass(PEXTERN)
+ // The actual type is [256]uint64, but we use [256*8]uint8 so we can address
+ // individual bytes.
+ staticuint64s.Type = types.NewArray(types.Types[TUINT8], 256*8)
+ zerobase = newname(Runtimepkg.Lookup("zerobase"))
+ zerobase.SetClass(PEXTERN)
+ zerobase.Type = types.Types[TUINTPTR]
+ }
+
+ // Optimize convT2{E,I} for many cases in which T is not pointer-shaped,
+ // by using an existing addressable value identical to n.Left
+ // or creating one on the stack.
+ var value *Node
+ switch {
+ case fromType.Size() == 0:
+ // n.Left is zero-sized. Use zerobase.
+ cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246.
+ value = zerobase
+ case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()):
+ // n.Left is a bool/byte. Use staticuint64s[n.Left * 8] on little-endian
+ // and staticuint64s[n.Left * 8 + 7] on big-endian.
+ n.Left = cheapexpr(n.Left, init)
+ // byteindex widens n.Left so that the multiplication doesn't overflow.
+ index := nod(OLSH, byteindex(n.Left), nodintconst(3))
+ if thearch.LinkArch.ByteOrder == binary.BigEndian {
+ index = nod(OADD, index, nodintconst(7))
+ }
+ value = nod(OINDEX, staticuint64s, index)
+ value.SetBounded(true)
+ case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
+ // n.Left is a readonly global; use it directly.
+ value = n.Left
+ case !fromType.IsInterface() && n.Esc == EscNone && fromType.Width <= 1024:
+ // n.Left does not escape. Use a stack temporary initialized to n.Left.
+ value = temp(fromType)
+ init.Append(typecheck(nod(OAS, value, n.Left), ctxStmt))
+ }
+
+ if value != nil {
+ // Value is identical to n.Left.
+ // Construct the interface directly: {type/itab, &value}.
+ l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), ctxExpr))
+ l.Type = toType
+ l.SetTypecheck(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 toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
+ // Evaluate the input interface.
+ c := temp(fromType)
+ init.Append(nod(OAS, c, n.Left))
+
+ // Get the itab out of the interface.
+ tmp := temp(types.NewPtr(types.Types[TUINT8]))
+ init.Append(nod(OAS, tmp, typecheck(nod(OITAB, c, nil), ctxExpr)))
+
+ // Get the type out of the itab.
+ nif := nod(OIF, typecheck(nod(ONE, tmp, nodnil()), ctxExpr), nil)
+ nif.Nbody.Set1(nod(OAS, tmp, itabType(tmp)))
+ init.Append(nif)
+
+ // Build the result.
+ e := nod(OEFACE, tmp, ifaceData(n.Pos, c, types.NewPtr(types.Types[TUINT8])))
+ e.Type = toType // assign type manually, typecheck doesn't understand OEFACE.
+ e.SetTypecheck(1)
+ n = e
+ break
+ }
+
+ fnname, needsaddr := convFuncName(fromType, toType)
+
+ if !needsaddr && !fromType.IsInterface() {
+ // Use a specialized conversion routine that only returns a data pointer.
+ // ptr = convT2X(val)
+ // e = iface{typ/tab, ptr}
+ fn := syslook(fnname)
+ dowidth(fromType)
+ fn = substArgTypes(fn, fromType)
+ dowidth(fn.Type)
+ call := nod(OCALL, fn, nil)
+ call.List.Set1(n.Left)
+ call = typecheck(call, ctxExpr)
+ call = walkexpr(call, init)
+ call = safeexpr(call, init)
+ e := nod(OEFACE, typeword(), call)
+ e.Type = toType
+ e.SetTypecheck(1)
+ n = e
+ break
+ }
+
+ var tab *Node
+ if fromType.IsInterface() {
+ // convI2I
+ tab = typename(toType)
+ } else {
+ // convT2x
+ tab = typeword()
+ }
+
+ v := n.Left
+ if needsaddr {
+ // Types of large or unknown size are passed by reference.
+ // Orderexpr arranged for n.Left to be a temporary for all
+ // the conversions it could see. Comparison of an interface
+ // with a non-interface, especially in a switch on interface value
+ // with non-interface cases, is not visible to order.stmt, so we
+ // have to fall back on allocating a temp here.
+ if !islvalue(v) {
+ v = copyexpr(v, v.Type, init)
+ }
+ v = nod(OADDR, v, nil)
+ }
+
+ dowidth(fromType)
+ fn := syslook(fnname)
+ fn = substArgTypes(fn, fromType, toType)
+ dowidth(fn.Type)
+ n = nod(OCALL, fn, nil)
+ n.List.Set2(tab, v)
+ n = typecheck(n, ctxExpr)
+ n = walkexpr(n, init)
+
+ case OCONV, OCONVNOP:
+ n.Left = walkexpr(n.Left, init)
+ if n.Op == OCONVNOP && checkPtr(Curfn, 1) {
+ if n.Type.IsPtr() && n.Left.Type.IsUnsafePtr() { // unsafe.Pointer to *T
+ n = walkCheckPtrAlignment(n, init, nil)
+ break
+ }
+ if n.Type.IsUnsafePtr() && n.Left.Type.IsUintptr() { // uintptr to unsafe.Pointer
+ n = walkCheckPtrArithmetic(n, init)
+ break
+ }
+ }
+ param, result := rtconvfn(n.Left.Type, n.Type)
+ if param == Txxx {
+ break
+ }
+ fn := basicnames[param] + "to" + basicnames[result]
+ n = conv(mkcall(fn, types.Types[result], init, conv(n.Left, types.Types[param])), n.Type)
+
+ case ODIV, OMOD:
+ n.Left = walkexpr(n.Left, init)
+ n.Right = walkexpr(n.Right, init)
+
+ // rewrite complex div into function call.
+ et := n.Left.Type.Etype
+
+ if isComplex[et] && n.Op == ODIV {
+ t := n.Type
+ n = mkcall("complex128div", types.Types[TCOMPLEX128], init, conv(n.Left, types.Types[TCOMPLEX128]), conv(n.Right, types.Types[TCOMPLEX128]))
+ n = conv(n, t)
+ break
+ }
+
+ // Nothing to do for float divisions.
+ if isFloat[et] {
+ break
+ }
+
+ // rewrite 64-bit div and mod on 32-bit architectures.
+ // TODO: Remove this code once we can introduce
+ // runtime calls late in SSA processing.
+ if Widthreg < 8 && (et == TINT64 || et == TUINT64) {
+ if n.Right.Op == OLITERAL {
+ // Leave div/mod by constant powers of 2 or small 16-bit constants.
+ // The SSA backend will handle those.
+ switch et {
+ case TINT64:
+ c := n.Right.Int64Val()
+ if c < 0 {
+ c = -c
+ }
+ if c != 0 && c&(c-1) == 0 {
+ break opswitch
+ }
+ case TUINT64:
+ c := uint64(n.Right.Int64Val())
+ if c < 1<<16 {
+ break opswitch
+ }
+ if c != 0 && c&(c-1) == 0 {
+ break opswitch
+ }
+ }
+ }
+ var fn string
+ if et == TINT64 {
+ fn = "int64"
+ } else {
+ fn = "uint64"
+ }
+ if n.Op == ODIV {
+ fn += "div"
+ } else {
+ fn += "mod"
+ }
+ n = mkcall(fn, n.Type, init, conv(n.Left, types.Types[et]), conv(n.Right, types.Types[et]))
+ }
+
+ case OINDEX:
+ n.Left = walkexpr(n.Left, init)
+
+ // save the original node for bounds checking elision.
+ // If it was a ODIV/OMOD walk might rewrite it.
+ r := n.Right
+
+ n.Right = walkexpr(n.Right, init)
+
+ // if range of type cannot exceed static array bound,
+ // disable bounds check.
+ if n.Bounded() {
+ break
+ }
+ t := n.Left.Type
+ if t != nil && t.IsPtr() {
+ t = t.Elem()
+ }
+ if t.IsArray() {
+ n.SetBounded(bounded(r, t.NumElem()))
+ if Debug.m != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
+ Warn("index bounds check elided")
+ }
+ if smallintconst(n.Right) && !n.Bounded() {
+ yyerror("index out of bounds")
+ }
+ } else if Isconst(n.Left, CTSTR) {
+ n.SetBounded(bounded(r, int64(len(n.Left.StringVal()))))
+ 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 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")
+ }
+ }
+
+ case OINDEXMAP:
+ // Replace m[k] with *map{access1,assign}(maptype, m, &k)
+ n.Left = walkexpr(n.Left, init)
+ n.Right = walkexpr(n.Right, init)
+ map_ := n.Left
+ key := n.Right
+ t := map_.Type
+ if n.IndexMapLValue() {
+ // This m[k] expression is on the left-hand side of an assignment.
+ fast := mapfast(t)
+ if fast == mapslow {
+ // standard version takes key by reference.
+ // order.expr made sure key is addressable.
+ key = nod(OADDR, key, nil)
+ }
+ n = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)
+ } else {
+ // m[k] is not the target of an assignment.
+ fast := mapfast(t)
+ if fast == mapslow {
+ // standard version takes key by reference.
+ // order.expr made sure key is addressable.
+ key = nod(OADDR, key, nil)
+ }
+
+ if w := t.Elem().Width; w <= zeroValSize {
+ n = mkcall1(mapfn(mapaccess1[fast], t), types.NewPtr(t.Elem()), init, typename(t), map_, key)
+ } else {
+ z := zeroaddr(w)
+ n = mkcall1(mapfn("mapaccess1_fat", t), types.NewPtr(t.Elem()), init, typename(t), map_, key, z)
+ }
+ }
+ n.Type = types.NewPtr(t.Elem())
+ n.MarkNonNil() // mapaccess1* and mapassign always return non-nil pointers.
+ n = nod(ODEREF, n, nil)
+ n.Type = t.Elem()
+ n.SetTypecheck(1)
+
+ case ORECV:
+ Fatalf("walkexpr ORECV") // should see inside OAS only
+
+ case OSLICEHEADER:
+ n.Left = walkexpr(n.Left, init)
+ n.List.SetFirst(walkexpr(n.List.First(), init))
+ n.List.SetSecond(walkexpr(n.List.Second(), init))
+
+ case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+ checkSlice := checkPtr(Curfn, 1) && n.Op == OSLICE3ARR && n.Left.Op == OCONVNOP && n.Left.Left.Type.IsUnsafePtr()
+ if checkSlice {
+ n.Left.Left = walkexpr(n.Left.Left, init)
+ } else {
+ n.Left = walkexpr(n.Left, init)
+ }
+ low, high, max := n.SliceBounds()
+ low = walkexpr(low, init)
+ if low != nil && isZero(low) {
+ // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k].
+ low = nil
+ }
+ high = walkexpr(high, init)
+ max = walkexpr(max, init)
+ n.SetSliceBounds(low, high, max)
+ if checkSlice {
+ n.Left = walkCheckPtrAlignment(n.Left, init, max)
+ }
+ if n.Op.IsSlice3() {
+ if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
+ // Reduce x[i:j:cap(x)] to x[i:j].
+ if n.Op == OSLICE3 {
+ n.Op = OSLICE
+ } else {
+ n.Op = OSLICEARR
+ }
+ n = reduceSlice(n)
+ }
+ } else {
+ n = reduceSlice(n)
+ }
+
+ case ONEW:
+ if n.Type.Elem().NotInHeap() {
+ yyerror("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type.Elem())
+ }
+ if n.Esc == EscNone {
+ if n.Type.Elem().Width >= maxImplicitStackVarSize {
+ Fatalf("large ONEW with EscNone: %v", n)
+ }
+ r := temp(n.Type.Elem())
+ r = nod(OAS, r, nil) // zero temp
+ r = typecheck(r, ctxStmt)
+ init.Append(r)
+ r = nod(OADDR, r.Left, nil)
+ r = typecheck(r, ctxExpr)
+ n = r
+ } else {
+ n = callnew(n.Type.Elem())
+ }
+
+ case OADDSTR:
+ n = addstr(n, init)
+
+ case OAPPEND:
+ // order should make sure we only see OAS(node, OAPPEND), which we handle above.
+ Fatalf("append outside assignment")
+
+ case OCOPY:
+ n = copyany(n, init, instrumenting && !compiling_runtime)
+
+ // cannot use chanfn - closechan takes any, not chan any
+ case OCLOSE:
+ fn := syslook("closechan")
+
+ fn = substArgTypes(fn, n.Left.Type)
+ n = mkcall1(fn, nil, init, n.Left)
+
+ case OMAKECHAN:
+ // When size fits into int, use makechan instead of
+ // makechan64, which is faster and shorter on 32 bit platforms.
+ size := n.Left
+ fnname := "makechan64"
+ argtype := types.Types[TINT64]
+
+ // Type checking guarantees that TIDEAL size is positive and fits in an int.
+ // The case of size overflow when converting TUINT or TUINTPTR to TINT
+ // will be handled by the negative range checks in makechan during runtime.
+ if size.Type.IsKind(TIDEAL) || maxintval[size.Type.Etype].Cmp(maxintval[TUINT]) <= 0 {
+ fnname = "makechan"
+ argtype = types.Types[TINT]
+ }
+
+ n = mkcall1(chanfn(fnname, 1, n.Type), n.Type, init, typename(n.Type), conv(size, argtype))
+
+ case OMAKEMAP:
+ t := n.Type
+ hmapType := hmap(t)
+ hint := n.Left
+
+ // var h *hmap
+ var h *Node
+ if n.Esc == EscNone {
+ // Allocate hmap on stack.
+
+ // var hv hmap
+ hv := temp(hmapType)
+ zero := nod(OAS, hv, nil)
+ zero = typecheck(zero, ctxStmt)
+ init.Append(zero)
+ // h = &hv
+ h = nod(OADDR, hv, nil)
+
+ // Allocate one bucket pointed to by hmap.buckets on stack if hint
+ // is not larger than BUCKETSIZE. In case hint is larger than
+ // BUCKETSIZE runtime.makemap will allocate the buckets on the heap.
+ // Maximum key and elem size is 128 bytes, larger objects
+ // are stored with an indirection. So max bucket size is 2048+eps.
+ if !Isconst(hint, CTINT) ||
+ hint.Val().U.(*Mpint).CmpInt64(BUCKETSIZE) <= 0 {
+
+ // In case hint is larger than BUCKETSIZE runtime.makemap
+ // will allocate the buckets on the heap, see #20184
+ //
+ // if hint <= BUCKETSIZE {
+ // var bv bmap
+ // b = &bv
+ // h.buckets = b
+ // }
+
+ nif := nod(OIF, nod(OLE, hint, nodintconst(BUCKETSIZE)), nil)
+ nif.SetLikely(true)
+
+ // var bv bmap
+ bv := temp(bmap(t))
+ zero = nod(OAS, bv, nil)
+ nif.Nbody.Append(zero)
+
+ // b = &bv
+ b := nod(OADDR, bv, nil)
+
+ // h.buckets = b
+ bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap
+ na := nod(OAS, nodSym(ODOT, h, bsym), b)
+ nif.Nbody.Append(na)
+
+ nif = typecheck(nif, ctxStmt)
+ nif = walkstmt(nif)
+ init.Append(nif)
+ }
+ }
+
+ if Isconst(hint, CTINT) && hint.Val().U.(*Mpint).CmpInt64(BUCKETSIZE) <= 0 {
+ // Handling make(map[any]any) and
+ // make(map[any]any, hint) where hint <= BUCKETSIZE
+ // special allows for faster map initialization and
+ // improves binary size by using calls with fewer arguments.
+ // For hint <= BUCKETSIZE overLoadFactor(hint, 0) is false
+ // and no buckets will be allocated by makemap. Therefore,
+ // no buckets need to be allocated in this code path.
+ if n.Esc == EscNone {
+ // Only need to initialize h.hash0 since
+ // hmap h has been allocated on the stack already.
+ // h.hash0 = fastrand()
+ rand := mkcall("fastrand", types.Types[TUINT32], init)
+ hashsym := hmapType.Field(4).Sym // hmap.hash0 see reflect.go:hmap
+ a := nod(OAS, nodSym(ODOT, h, hashsym), rand)
+ a = typecheck(a, ctxStmt)
+ a = walkexpr(a, init)
+ init.Append(a)
+ n = convnop(h, t)
+ } else {
+ // Call runtime.makehmap to allocate an
+ // hmap on the heap and initialize hmap's hash0 field.
+ fn := syslook("makemap_small")
+ fn = substArgTypes(fn, t.Key(), t.Elem())
+ n = mkcall1(fn, n.Type, init)
+ }
+ } else {
+ if n.Esc != EscNone {
+ h = nodnil()
+ }
+ // Map initialization with a variable or large hint is
+ // more complicated. We therefore generate a call to
+ // runtime.makemap to initialize hmap and allocate the
+ // map buckets.
+
+ // When hint fits into int, use makemap instead of
+ // makemap64, which is faster and shorter on 32 bit platforms.
+ fnname := "makemap64"
+ argtype := types.Types[TINT64]
+
+ // Type checking guarantees that TIDEAL hint is positive and fits in an int.
+ // See checkmake call in TMAP case of OMAKE case in OpSwitch in typecheck1 function.
+ // The case of hint overflow when converting TUINT or TUINTPTR to TINT
+ // will be handled by the negative range checks in makemap during runtime.
+ if hint.Type.IsKind(TIDEAL) || maxintval[hint.Type.Etype].Cmp(maxintval[TUINT]) <= 0 {
+ fnname = "makemap"
+ argtype = types.Types[TINT]
+ }
+
+ fn := syslook(fnname)
+ fn = substArgTypes(fn, hmapType, t.Key(), t.Elem())
+ n = mkcall1(fn, n.Type, init, typename(n.Type), conv(hint, argtype), h)
+ }
+
+ case OMAKESLICE:
+ l := n.Left
+ r := n.Right
+ if r == nil {
+ r = safeexpr(l, init)
+ l = r
+ }
+ t := n.Type
+ if t.Elem().NotInHeap() {
+ yyerror("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
+ }
+ if n.Esc == EscNone {
+ if why := heapAllocReason(n); why != "" {
+ Fatalf("%v has EscNone, but %v", n, why)
+ }
+ // var arr [r]T
+ // n = arr[:l]
+ i := indexconst(r)
+ if i < 0 {
+ Fatalf("walkexpr: invalid index %v", r)
+ }
+
+ // cap is constrained to [0,2^31) or [0,2^63) depending on whether
+ // we're in 32-bit or 64-bit systems. So it's safe to do:
+ //
+ // if uint64(len) > cap {
+ // if len < 0 { panicmakeslicelen() }
+ // panicmakeslicecap()
+ // }
+ nif := nod(OIF, nod(OGT, conv(l, types.Types[TUINT64]), nodintconst(i)), nil)
+ niflen := nod(OIF, nod(OLT, l, nodintconst(0)), nil)
+ niflen.Nbody.Set1(mkcall("panicmakeslicelen", nil, init))
+ nif.Nbody.Append(niflen, mkcall("panicmakeslicecap", nil, init))
+ nif = typecheck(nif, ctxStmt)
+ init.Append(nif)
+
+ t = types.NewArray(t.Elem(), i) // [r]T
+ var_ := temp(t)
+ a := nod(OAS, var_, nil) // zero temp
+ a = typecheck(a, ctxStmt)
+ init.Append(a)
+ r := nod(OSLICE, var_, nil) // arr[:l]
+ r.SetSliceBounds(nil, l, nil)
+ r = conv(r, n.Type) // in case n.Type is named.
+ r = typecheck(r, ctxExpr)
+ r = walkexpr(r, init)
+ n = r
+ } else {
+ // 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.
+
+ len, cap := l, r
+
+ fnname := "makeslice64"
+ argtype := types.Types[TINT64]
+
+ // Type checking 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.Types[TINT]
+ }
+
+ m := nod(OSLICEHEADER, nil, nil)
+ m.Type = t
+
+ fn := syslook(fnname)
+ m.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
+ m.Left.MarkNonNil()
+ m.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT]))
+
+ m = typecheck(m, ctxExpr)
+ m = walkexpr(m, init)
+ n = m
+ }
+
+ case OMAKESLICECOPY:
+ if n.Esc == EscNone {
+ Fatalf("OMAKESLICECOPY with EscNone: %v", n)
+ }
+
+ t := n.Type
+ if t.Elem().NotInHeap() {
+ yyerror("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
+ }
+
+ length := conv(n.Left, types.Types[TINT])
+ copylen := nod(OLEN, n.Right, nil)
+ copyptr := nod(OSPTR, n.Right, nil)
+
+ if !t.Elem().HasPointers() && n.Bounded() {
+ // When len(to)==len(from) and elements have no pointers:
+ // replace make+copy with runtime.mallocgc+runtime.memmove.
+
+ // We do not check for overflow of len(to)*elem.Width here
+ // since len(from) is an existing checked slice capacity
+ // with same elem.Width for the from slice.
+ size := nod(OMUL, conv(length, types.Types[TUINTPTR]), conv(nodintconst(t.Elem().Width), types.Types[TUINTPTR]))
+
+ // instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
+ fn := syslook("mallocgc")
+ sh := nod(OSLICEHEADER, nil, nil)
+ sh.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, size, nodnil(), nodbool(false))
+ sh.Left.MarkNonNil()
+ sh.List.Set2(length, length)
+ sh.Type = t
+
+ s := temp(t)
+ r := typecheck(nod(OAS, s, sh), ctxStmt)
+ r = walkexpr(r, init)
+ init.Append(r)
+
+ // instantiate memmove(to *any, frm *any, size uintptr)
+ fn = syslook("memmove")
+ fn = substArgTypes(fn, t.Elem(), t.Elem())
+ ncopy := mkcall1(fn, nil, init, nod(OSPTR, s, nil), copyptr, size)
+ ncopy = typecheck(ncopy, ctxStmt)
+ ncopy = walkexpr(ncopy, init)
+ init.Append(ncopy)
+
+ n = s
+ } else { // Replace make+copy with runtime.makeslicecopy.
+ // instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
+ fn := syslook("makeslicecopy")
+ s := nod(OSLICEHEADER, nil, nil)
+ s.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[TUNSAFEPTR]))
+ s.Left.MarkNonNil()
+ s.List.Set2(length, length)
+ s.Type = t
+ n = typecheck(s, ctxExpr)
+ n = walkexpr(n, init)
+ }
+
+ case ORUNESTR:
+ a := nodnil()
+ if n.Esc == EscNone {
+ t := types.NewArray(types.Types[TUINT8], 4)
+ a = nod(OADDR, temp(t), nil)
+ }
+ // intstring(*[4]byte, rune)
+ n = mkcall("intstring", n.Type, init, a, conv(n.Left, types.Types[TINT64]))
+
+ case OBYTES2STR, ORUNES2STR:
+ a := nodnil()
+ if n.Esc == EscNone {
+ // Create temporary buffer for string on stack.
+ t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
+ a = nod(OADDR, temp(t), nil)
+ }
+ if n.Op == ORUNES2STR {
+ // slicerunetostring(*[32]byte, []rune) string
+ n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
+ } else {
+ // slicebytetostring(*[32]byte, ptr *byte, n int) string
+ n.Left = cheapexpr(n.Left, init)
+ ptr, len := n.Left.backingArrayPtrLen()
+ n = mkcall("slicebytetostring", n.Type, init, a, ptr, len)
+ }
+
+ case OBYTES2STRTMP:
+ n.Left = walkexpr(n.Left, init)
+ if !instrumenting {
+ // Let the backend handle OBYTES2STRTMP directly
+ // to avoid a function call to slicebytetostringtmp.
+ break
+ }
+ // slicebytetostringtmp(ptr *byte, n int) string
+ n.Left = cheapexpr(n.Left, init)
+ ptr, len := n.Left.backingArrayPtrLen()
+ n = mkcall("slicebytetostringtmp", n.Type, init, ptr, len)
+
+ case OSTR2BYTES:
+ s := n.Left
+ if Isconst(s, CTSTR) {
+ sc := s.StringVal()
+
+ // Allocate a [n]byte of the right size.
+ t := types.NewArray(types.Types[TUINT8], int64(len(sc)))
+ var a *Node
+ if n.Esc == EscNone && len(sc) <= int(maxImplicitStackVarSize) {
+ a = nod(OADDR, temp(t), nil)
+ } else {
+ a = callnew(t)
+ }
+ p := temp(t.PtrTo()) // *[n]byte
+ init.Append(typecheck(nod(OAS, p, a), ctxStmt))
+
+ // Copy from the static string data to the [n]byte.
+ if len(sc) > 0 {
+ as := nod(OAS,
+ nod(ODEREF, p, nil),
+ nod(ODEREF, convnop(nod(OSPTR, s, nil), t.PtrTo()), nil))
+ as = typecheck(as, ctxStmt)
+ as = walkstmt(as)
+ init.Append(as)
+ }
+
+ // Slice the [n]byte to a []byte.
+ n.Op = OSLICEARR
+ n.Left = p
+ n = walkexpr(n, init)
+ break
+ }
+
+ a := nodnil()
+ if n.Esc == EscNone {
+ // Create temporary buffer for slice on stack.
+ t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
+ a = nod(OADDR, temp(t), nil)
+ }
+ // stringtoslicebyte(*32[byte], string) []byte
+ n = mkcall("stringtoslicebyte", n.Type, init, a, conv(s, types.Types[TSTRING]))
+
+ case OSTR2BYTESTMP:
+ // []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)
+
+ case OSTR2RUNES:
+ a := nodnil()
+ if n.Esc == EscNone {
+ // Create temporary buffer for slice on stack.
+ t := types.NewArray(types.Types[TINT32], tmpstringbufsize)
+ a = nod(OADDR, temp(t), nil)
+ }
+ // stringtoslicerune(*[32]rune, string) []rune
+ n = mkcall("stringtoslicerune", n.Type, init, a, conv(n.Left, types.Types[TSTRING]))
+
+ case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
+ if isStaticCompositeLiteral(n) && !canSSAType(n.Type) {
+ // n can be directly represented in the read-only data section.
+ // Make direct reference to the static data. See issue 12841.
+ vstat := readonlystaticname(n.Type)
+ fixedlit(inInitFunction, initKindStatic, n, vstat, init)
+ n = vstat
+ n = typecheck(n, ctxExpr)
+ break
+ }
+ var_ := temp(n.Type)
+ 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)
+ n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, n.Left, n1)
+
+ case OCLOSURE:
+ n = walkclosure(n, init)
+
+ case OCALLPART:
+ n = walkpartialcall(n, init)
+ }
+
+ // Expressions that are constant at run time but not
+ // considered const by the language spec are not turned into
+ // constants until walk. For example, if n is y%1 == 0, the
+ // walk of y%1 may have replaced it by 0.
+ // Check whether n with its updated args is itself now a constant.
+ t := n.Type
+ evconst(n)
+ if n.Type != t {
+ Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type)
+ }
+ if n.Op == OLITERAL {
+ n = typecheck(n, ctxExpr)
+ // Emit string symbol now to avoid emitting
+ // any concurrently during the backend.
+ if s, ok := n.Val().U.(string); ok {
+ _ = stringsym(n.Pos, s)
+ }
+ }
+
+ updateHasCall(n)
+
+ if Debug.w != 0 && n != nil {
+ Dump("after walk expr", n)
+ }
+
+ lineno = lno
+ return n
+}
+
+// markTypeUsedInInterface marks that type t is converted to an interface.
+// This information is used in the linker in dead method elimination.
+func markTypeUsedInInterface(t *types.Type, from *obj.LSym) {
+ tsym := typenamesym(t).Linksym()
+ // Emit a marker relocation. The linker will know the type is converted
+ // to an interface if "from" is reachable.
+ r := obj.Addrel(from)
+ r.Sym = tsym
+ r.Type = objabi.R_USEIFACE
+}
+
+// markUsedIfaceMethod marks that an interface method is used in the current
+// function. n is OCALLINTER node.
+func markUsedIfaceMethod(n *Node) {
+ ityp := n.Left.Left.Type
+ tsym := typenamesym(ityp).Linksym()
+ r := obj.Addrel(Curfn.Func.lsym)
+ r.Sym = tsym
+ // n.Left.Xoffset is the method index * Widthptr (the offset of code pointer
+ // in itab).
+ midx := n.Left.Xoffset / int64(Widthptr)
+ r.Add = ifaceMethodOffset(ityp, midx)
+ r.Type = objabi.R_USEIFACEMETHOD
+}
+
+// rtconvfn returns the parameter and result types that will be used by a
+// runtime function to convert from type src to type dst. The runtime function
+// name can be derived from the names of the returned types.
+//
+// If no such function is necessary, it returns (Txxx, Txxx).
+func rtconvfn(src, dst *types.Type) (param, result types.EType) {
+ if thearch.SoftFloat {
+ return Txxx, Txxx
+ }
+
+ switch thearch.LinkArch.Family {
+ case sys.ARM, sys.MIPS:
+ if src.IsFloat() {
+ switch dst.Etype {
+ case TINT64, TUINT64:
+ return TFLOAT64, dst.Etype
+ }
+ }
+ if dst.IsFloat() {
+ switch src.Etype {
+ case TINT64, TUINT64:
+ return src.Etype, TFLOAT64
+ }
+ }
+
+ case sys.I386:
+ if src.IsFloat() {
+ switch dst.Etype {
+ case TINT64, TUINT64:
+ return TFLOAT64, dst.Etype
+ case TUINT32, TUINT, TUINTPTR:
+ return TFLOAT64, TUINT32
+ }
+ }
+ if dst.IsFloat() {
+ switch src.Etype {
+ case TINT64, TUINT64:
+ return src.Etype, TFLOAT64
+ case TUINT32, TUINT, TUINTPTR:
+ return TUINT32, TFLOAT64
+ }
+ }
+ }
+ return Txxx, Txxx
+}
+
+// TODO(josharian): combine this with its caller and simplify
+func reduceSlice(n *Node) *Node {
+ low, high, max := n.SliceBounds()
+ if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
+ // Reduce x[i:len(x)] to x[i:].
+ high = nil
+ }
+ n.SetSliceBounds(low, high, max)
+ if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil {
+ // Reduce x[:] to x.
+ if Debug_slice > 0 {
+ Warn("slice: omit slice operation")
+ }
+ return n.Left
+ }
+ return n
+}
+
+func ascompatee1(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)
+
+ if l.Op == OINDEXMAP {
+ return n
+ }
+
+ return convas(n, init)
+}
+
+func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
+ // check assign expression list to
+ // an expression list. called in
+ // expr-list = expr-list
+
+ // ensure order of evaluation for function calls
+ for i := range nl {
+ nl[i] = safeexpr(nl[i], init)
+ }
+ for i1 := range nr {
+ nr[i1] = safeexpr(nr[i1], init)
+ }
+
+ var nn []*Node
+ i := 0
+ for ; i < len(nl); i++ {
+ if i >= len(nr) {
+ break
+ }
+ // Do not generate 'x = x' during return. See issue 4014.
+ if op == ORETURN && samesafeexpr(nl[i], nr[i]) {
+ continue
+ }
+ nn = append(nn, ascompatee1(nl[i], nr[i], init))
+ }
+
+ // cannot happen: caller checked that lists had same length
+ if i < len(nl) || i < len(nr) {
+ var nln, nrn Nodes
+ nln.Set(nl)
+ nrn.Set(nr)
+ Fatalf("error in shape across %+v %v %+v / %d %d [%s]", nln, op, nrn, len(nl), len(nr), Curfn.funcname())
+ }
+ return nn
+}
+
+// fncall reports whether assigning an rvalue of type rt to an lvalue l might involve a function call.
+func fncall(l *Node, rt *types.Type) bool {
+ if l.HasCall() || l.Op == OINDEXMAP {
+ return true
+ }
+ if types.Identical(l.Type, rt) {
+ return false
+ }
+ // There might be a conversion required, which might involve a runtime call.
+ return true
+}
+
+// check assign type list to
+// an expression list. called in
+// expr-list = func()
+func ascompatet(nl Nodes, nr *types.Type) []*Node {
+ if nl.Len() != nr.NumFields() {
+ Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
+ }
+
+ var nn, mm Nodes
+ for i, l := range nl.Slice() {
+ if l.isBlank() {
+ continue
+ }
+ r := nr.Field(i)
+
+ // Any assignment to an lvalue that might cause a function call must be
+ // deferred until all the returned values have been read.
+ if fncall(l, r.Type) {
+ tmp := temp(r.Type)
+ tmp = typecheck(tmp, ctxExpr)
+ a := nod(OAS, l, tmp)
+ a = convas(a, &mm)
+ mm.Append(a)
+ l = tmp
+ }
+
+ res := nod(ORESULT, nil, nil)
+ res.Xoffset = Ctxt.FixedFrameSize() + r.Offset
+ res.Type = r.Type
+ res.SetTypecheck(1)
+
+ a := nod(OAS, l, res)
+ a = convas(a, &nn)
+ updateHasCall(a)
+ if a.HasCall() {
+ Dump("ascompatet ucount", a)
+ Fatalf("ascompatet: too many function calls evaluating parameters")
+ }
+
+ nn.Append(a)
+ }
+ return append(nn.Slice(), mm.Slice()...)
+}
+
+// package all the arguments that match a ... T parameter into a []T.
+func mkdotargslice(typ *types.Type, args []*Node) *Node {
+ var n *Node
+ if len(args) == 0 {
+ n = nodnil()
+ n.Type = typ
+ } else {
+ n = nod(OCOMPLIT, nil, typenod(typ))
+ n.List.Append(args...)
+ n.SetImplicit(true)
+ }
+
+ n = typecheck(n, ctxExpr)
+ if n.Type == nil {
+ Fatalf("mkdotargslice: typecheck failed")
+ }
+ return n
+}
+
+// fixVariadicCall rewrites calls to variadic functions to use an
+// explicit ... argument if one is not already present.
+func fixVariadicCall(call *Node) {
+ fntype := call.Left.Type
+ if !fntype.IsVariadic() || call.IsDDD() {
+ return
+ }
+
+ vi := fntype.NumParams() - 1
+ vt := fntype.Params().Field(vi).Type
+
+ args := call.List.Slice()
+ extra := args[vi:]
+ slice := mkdotargslice(vt, extra)
+ for i := range extra {
+ extra[i] = nil // allow GC
+ }
+
+ call.List.Set(append(args[:vi], slice))
+ call.SetIsDDD(true)
+}
+
+func walkCall(n *Node, init *Nodes) {
+ if n.Rlist.Len() != 0 {
+ return // already walked
+ }
+
+ params := n.Left.Type.Params()
+ args := n.List.Slice()
+
+ n.Left = walkexpr(n.Left, init)
+ walkexprlist(args, init)
+
+ // If this is a method call, add the receiver at the beginning of the args.
+ if n.Op == OCALLMETH {
+ withRecv := make([]*Node, len(args)+1)
+ withRecv[0] = n.Left.Left
+ n.Left.Left = nil
+ copy(withRecv[1:], args)
+ args = withRecv
+ }
+
+ // For any argument whose evaluation might require a function call,
+ // store that argument into a temporary variable,
+ // to prevent that calls from clobbering arguments already on the stack.
+ // When instrumenting, all arguments might require function calls.
+ var tempAssigns []*Node
+ for i, arg := range args {
+ updateHasCall(arg)
+ // Determine param type.
+ var t *types.Type
+ if n.Op == OCALLMETH {
+ if i == 0 {
+ t = n.Left.Type.Recv().Type
+ } else {
+ t = params.Field(i - 1).Type
+ }
+ } else {
+ t = params.Field(i).Type
+ }
+ if instrumenting || fncall(arg, t) {
+ // make assignment of fncall to tempAt
+ tmp := temp(t)
+ a := nod(OAS, tmp, arg)
+ a = convas(a, init)
+ tempAssigns = append(tempAssigns, a)
+ // replace arg with temp
+ args[i] = tmp
+ }
+ }
+
+ n.List.Set(tempAssigns)
+ n.Rlist.Set(args)
+}
+
+// generate code for print
+func walkprint(nn *Node, init *Nodes) *Node {
+ // Hoist all the argument evaluation up before the lock.
+ walkexprlistcheap(nn.List.Slice(), init)
+
+ // For println, add " " between elements and "\n" at the end.
+ if nn.Op == OPRINTN {
+ s := nn.List.Slice()
+ t := make([]*Node, 0, len(s)*2)
+ for i, n := range s {
+ if i != 0 {
+ t = append(t, nodstr(" "))
+ }
+ t = append(t, n)
+ }
+ t = append(t, nodstr("\n"))
+ nn.List.Set(t)
+ }
+
+ // Collapse runs of constant strings.
+ s := nn.List.Slice()
+ t := make([]*Node, 0, len(s))
+ for i := 0; i < len(s); {
+ var strs []string
+ for i < len(s) && Isconst(s[i], CTSTR) {
+ strs = append(strs, s[i].StringVal())
+ i++
+ }
+ if len(strs) > 0 {
+ t = append(t, nodstr(strings.Join(strs, "")))
+ }
+ if i < len(s) {
+ t = append(t, s[i])
+ i++
+ }
+ }
+ nn.List.Set(t)
+
+ calls := []*Node{mkcall("printlock", nil, init)}
+ for i, n := range nn.List.Slice() {
+ if n.Op == OLITERAL {
+ switch n.Val().Ctype() {
+ case CTRUNE:
+ n = defaultlit(n, types.Runetype)
+
+ case CTINT:
+ n = defaultlit(n, types.Types[TINT64])
+
+ case CTFLT:
+ n = defaultlit(n, types.Types[TFLOAT64])
+ }
+ }
+
+ if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
+ n = defaultlit(n, types.Types[TINT64])
+ }
+ n = defaultlit(n, nil)
+ nn.List.SetIndex(i, n)
+ if n.Type == nil || n.Type.Etype == TFORW {
+ continue
+ }
+
+ var on *Node
+ switch n.Type.Etype {
+ case TINTER:
+ if n.Type.IsEmptyInterface() {
+ on = syslook("printeface")
+ } else {
+ on = syslook("printiface")
+ }
+ on = substArgTypes(on, n.Type) // any-1
+ case TPTR:
+ if n.Type.Elem().NotInHeap() {
+ on = syslook("printuintptr")
+ n = nod(OCONV, n, nil)
+ n.Type = types.Types[TUNSAFEPTR]
+ n = nod(OCONV, n, nil)
+ n.Type = types.Types[TUINTPTR]
+ break
+ }
+ fallthrough
+ case TCHAN, TMAP, TFUNC, TUNSAFEPTR:
+ on = syslook("printpointer")
+ on = substArgTypes(on, n.Type) // any-1
+ case TSLICE:
+ on = syslook("printslice")
+ on = substArgTypes(on, n.Type) // any-1
+ case TUINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINTPTR:
+ if isRuntimePkg(n.Type.Sym.Pkg) && n.Type.Sym.Name == "hex" {
+ on = syslook("printhex")
+ } else {
+ on = syslook("printuint")
+ }
+ case TINT, TINT8, TINT16, TINT32, TINT64:
+ on = syslook("printint")
+ case TFLOAT32, TFLOAT64:
+ on = syslook("printfloat")
+ case TCOMPLEX64, TCOMPLEX128:
+ on = syslook("printcomplex")
+ case TBOOL:
+ on = syslook("printbool")
+ case TSTRING:
+ cs := ""
+ if Isconst(n, CTSTR) {
+ cs = n.StringVal()
+ }
+ switch cs {
+ case " ":
+ on = syslook("printsp")
+ case "\n":
+ on = syslook("printnl")
+ default:
+ on = syslook("printstring")
+ }
+ default:
+ badtype(OPRINT, n.Type, nil)
+ continue
+ }
+
+ r := nod(OCALL, on, nil)
+ if params := on.Type.Params().FieldSlice(); len(params) > 0 {
+ t := params[0].Type
+ if !types.Identical(t, n.Type) {
+ n = nod(OCONV, n, nil)
+ n.Type = t
+ }
+ r.List.Append(n)
+ }
+ calls = append(calls, r)
+ }
+
+ calls = append(calls, mkcall("printunlock", nil, init))
+
+ typecheckslice(calls, ctxStmt)
+ walkexprlist(calls, init)
+
+ r := nod(OEMPTY, nil, nil)
+ r = typecheck(r, ctxStmt)
+ r = walkexpr(r, init)
+ r.Ninit.Set(calls)
+ return r
+}
+
+func callnew(t *types.Type) *Node {
+ dowidth(t)
+ n := nod(ONEWOBJ, typename(t), nil)
+ n.Type = types.NewPtr(t)
+ n.SetTypecheck(1)
+ n.MarkNonNil()
+ return n
+}
+
+// isReflectHeaderDataField reports whether l is an expression p.Data
+// where p has type reflect.SliceHeader or reflect.StringHeader.
+func isReflectHeaderDataField(l *Node) bool {
+ if l.Type != types.Types[TUINTPTR] {
+ return false
+ }
+
+ var tsym *types.Sym
+ switch l.Op {
+ case ODOT:
+ tsym = l.Left.Type.Sym
+ case ODOTPTR:
+ tsym = l.Left.Type.Elem().Sym
+ default:
+ return false
+ }
+
+ if tsym == nil || l.Sym.Name != "Data" || tsym.Pkg.Path != "reflect" {
+ return false
+ }
+ return tsym.Name == "SliceHeader" || tsym.Name == "StringHeader"
+}
+
+func convas(n *Node, init *Nodes) *Node {
+ if n.Op != OAS {
+ Fatalf("convas: not OAS %v", n.Op)
+ }
+ defer updateHasCall(n)
+
+ n.SetTypecheck(1)
+
+ if n.Left == nil || n.Right == nil {
+ return n
+ }
+
+ lt := n.Left.Type
+ rt := n.Right.Type
+ if lt == nil || rt == nil {
+ return n
+ }
+
+ if n.Left.isBlank() {
+ n.Right = defaultlit(n.Right, nil)
+ return n
+ }
+
+ if !types.Identical(lt, rt) {
+ n.Right = assignconv(n.Right, lt, "assignment")
+ n.Right = walkexpr(n.Right, init)
+ }
+ dowidth(n.Right.Type)
+
+ return n
+}
+
+// from ascompat[ee]
+// a,b = c,d
+// simultaneous assignment. there cannot
+// be later use of an earlier lvalue.
+//
+// function calls have been removed.
+func reorder3(all []*Node) []*Node {
+ // If a needed expression may be affected by an
+ // earlier assignment, make an early copy of that
+ // expression and use the copy instead.
+ var early []*Node
+
+ var mapinit Nodes
+ for i, n := range all {
+ l := n.Left
+
+ // Save subexpressions needed on left side.
+ // Drill through non-dereferences.
+ for {
+ if l.Op == ODOT || l.Op == OPAREN {
+ l = l.Left
+ continue
+ }
+
+ if l.Op == OINDEX && l.Left.Type.IsArray() {
+ l.Right = reorder3save(l.Right, all, i, &early)
+ l = l.Left
+ continue
+ }
+
+ break
+ }
+
+ switch l.Op {
+ default:
+ Fatalf("reorder3 unexpected lvalue %#v", l.Op)
+
+ case ONAME:
+ break
+
+ case OINDEX, OINDEXMAP:
+ l.Left = reorder3save(l.Left, all, i, &early)
+ l.Right = reorder3save(l.Right, all, i, &early)
+ if l.Op == OINDEXMAP {
+ all[i] = convas(all[i], &mapinit)
+ }
+
+ case ODEREF, ODOTPTR:
+ l.Left = reorder3save(l.Left, all, i, &early)
+ }
+
+ // Save expression on right side.
+ all[i].Right = reorder3save(all[i].Right, all, i, &early)
+ }
+
+ early = append(mapinit.Slice(), early...)
+ return append(early, all...)
+}
+
+// if the evaluation of *np would be affected by the
+// assignments in all up to but not including the ith assignment,
+// copy into a temporary during *early and
+// replace *np with that temp.
+// The result of reorder3save MUST be assigned back to n, e.g.
+// n.Left = reorder3save(n.Left, all, i, early)
+func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
+ if !aliased(n, all[:i]) {
+ return n
+ }
+
+ q := temp(n.Type)
+ q = nod(OAS, q, n)
+ q = typecheck(q, ctxStmt)
+ *early = append(*early, q)
+ return q.Left
+}
+
+// what's the outer value that a write to n affects?
+// outer value means containing struct or array.
+func outervalue(n *Node) *Node {
+ for {
+ switch n.Op {
+ case OXDOT:
+ Fatalf("OXDOT in walk")
+ case ODOT, OPAREN, OCONVNOP:
+ n = n.Left
+ continue
+ case OINDEX:
+ if n.Left.Type != nil && n.Left.Type.IsArray() {
+ n = n.Left
+ continue
+ }
+ }
+
+ return n
+ }
+}
+
+// Is it possible that the computation of r might be
+// affected by assignments in all?
+func aliased(r *Node, all []*Node) bool {
+ if r == nil {
+ return false
+ }
+
+ // Treat all fields of a struct as referring to the whole struct.
+ // We could do better but we would have to keep track of the fields.
+ for r.Op == ODOT {
+ r = r.Left
+ }
+
+ // Look for obvious aliasing: a variable being assigned
+ // during the all list and appearing in n.
+ // Also record whether there are any writes to addressable
+ // memory (either main memory or variables whose addresses
+ // have been taken).
+ memwrite := false
+ for _, as := range all {
+ // We can ignore assignments to blank.
+ if as.Left.isBlank() {
+ continue
+ }
+
+ l := outervalue(as.Left)
+ if l.Op != ONAME {
+ memwrite = true
+ continue
+ }
+
+ switch l.Class() {
+ default:
+ Fatalf("unexpected class: %v, %v", l, l.Class())
+
+ case PAUTOHEAP, PEXTERN:
+ memwrite = true
+ continue
+
+ case PPARAMOUT:
+ // Assignments to a result parameter in a function with defers
+ // becomes visible early if evaluation of any later expression
+ // panics (#43835).
+ if Curfn.Func.HasDefer() {
+ return true
+ }
+ fallthrough
+ case PAUTO, PPARAM:
+ if l.Name.Addrtaken() {
+ memwrite = true
+ continue
+ }
+
+ if vmatch2(l, r) {
+ // Direct hit: l appears in r.
+ return true
+ }
+ }
+ }
+
+ // The variables being written do not appear in r.
+ // However, r might refer to computed addresses
+ // that are being written.
+
+ // If no computed addresses are affected by the writes, no aliasing.
+ if !memwrite {
+ return false
+ }
+
+ // If r does not refer to computed addresses
+ // (that is, if r only refers to variables whose addresses
+ // have not been taken), no aliasing.
+ if varexpr(r) {
+ return false
+ }
+
+ // Otherwise, both the writes and r refer to computed memory addresses.
+ // Assume that they might conflict.
+ return true
+}
+
+// does the evaluation of n only refer to variables
+// whose addresses have not been taken?
+// (and no other memory)
+func varexpr(n *Node) bool {
+ if n == nil {
+ return true
+ }
+
+ switch n.Op {
+ case OLITERAL:
+ return true
+
+ case ONAME:
+ switch n.Class() {
+ case PAUTO, PPARAM, PPARAMOUT:
+ if !n.Name.Addrtaken() {
+ return true
+ }
+ }
+
+ return false
+
+ case OADD,
+ OSUB,
+ OOR,
+ OXOR,
+ OMUL,
+ ODIV,
+ OMOD,
+ OLSH,
+ ORSH,
+ OAND,
+ OANDNOT,
+ OPLUS,
+ ONEG,
+ OBITNOT,
+ OPAREN,
+ OANDAND,
+ OOROR,
+ OCONV,
+ OCONVNOP,
+ OCONVIFACE,
+ ODOTTYPE:
+ return varexpr(n.Left) && varexpr(n.Right)
+
+ case ODOT: // but not ODOTPTR
+ // Should have been handled in aliased.
+ Fatalf("varexpr unexpected ODOT")
+ }
+
+ // Be conservative.
+ return false
+}
+
+// is the name l mentioned in r?
+func vmatch2(l *Node, r *Node) bool {
+ if r == nil {
+ return false
+ }
+ switch r.Op {
+ // match each right given left
+ case ONAME:
+ return l == r
+
+ case OLITERAL:
+ return false
+ }
+
+ if vmatch2(l, r.Left) {
+ return true
+ }
+ if vmatch2(l, r.Right) {
+ return true
+ }
+ for _, n := range r.List.Slice() {
+ if vmatch2(l, n) {
+ return true
+ }
+ }
+ return false
+}
+
+// is any name mentioned in l also mentioned in r?
+// called by sinit.go
+func vmatch1(l *Node, r *Node) bool {
+ // isolate all left sides
+ if l == nil || r == nil {
+ return false
+ }
+ switch l.Op {
+ case ONAME:
+ switch l.Class() {
+ case PPARAM, PAUTO:
+ break
+
+ default:
+ // assignment to non-stack variable must be
+ // delayed if right has function calls.
+ if r.HasCall() {
+ return true
+ }
+ }
+
+ return vmatch2(l, r)
+
+ case OLITERAL:
+ return false
+ }
+
+ if vmatch1(l.Left, r) {
+ return true
+ }
+ if vmatch1(l.Right, r) {
+ return true
+ }
+ for _, n := range l.List.Slice() {
+ if vmatch1(n, r) {
+ return true
+ }
+ }
+ return false
+}
+
+// paramstoheap returns code to allocate memory for heap-escaped parameters
+// and to copy non-result parameters' values from the stack.
+func paramstoheap(params *types.Type) []*Node {
+ var nn []*Node
+ for _, t := range params.Fields().Slice() {
+ v := asNode(t.Nname)
+ if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
+ v = nil
+ }
+ if v == nil {
+ continue
+ }
+
+ if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
+ nn = append(nn, walkstmt(nod(ODCL, v, nil)))
+ if stackcopy.Class() == PPARAM {
+ nn = append(nn, walkstmt(typecheck(nod(OAS, v, stackcopy), ctxStmt)))
+ }
+ }
+ }
+
+ return nn
+}
+
+// zeroResults zeros the return values at the start of the function.
+// We need to do this very early in the function. Defer might stop a
+// panic and show the return values as they exist at the time of
+// panic. For precise stacks, the garbage collector assumes results
+// are always live, so we need to zero them before any allocations,
+// even allocations to move params/results to the heap.
+// The generated code is added to Curfn's Enter list.
+func zeroResults() {
+ for _, f := range Curfn.Type.Results().Fields().Slice() {
+ v := asNode(f.Nname)
+ if v != nil && v.Name.Param.Heapaddr != nil {
+ // The local which points to the return value is the
+ // thing that needs zeroing. This is already handled
+ // by a Needzero annotation in plive.go:livenessepilogue.
+ continue
+ }
+ if v.isParamHeapCopy() {
+ // TODO(josharian/khr): Investigate whether we can switch to "continue" here,
+ // and document more in either case.
+ // In the review of CL 114797, Keith wrote (roughly):
+ // I don't think the zeroing below matters.
+ // The stack return value will never be marked as live anywhere in the function.
+ // It is not written to until deferreturn returns.
+ v = v.Name.Param.Stackcopy
+ }
+ // Zero the stack location containing f.
+ Curfn.Func.Enter.Append(nodl(Curfn.Pos, OAS, v, nil))
+ }
+}
+
+// returnsfromheap returns code to copy values for heap-escaped parameters
+// back to the stack.
+func returnsfromheap(params *types.Type) []*Node {
+ var nn []*Node
+ for _, t := range params.Fields().Slice() {
+ v := asNode(t.Nname)
+ if v == nil {
+ continue
+ }
+ if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class() == PPARAMOUT {
+ nn = append(nn, walkstmt(typecheck(nod(OAS, stackcopy, v), ctxStmt)))
+ }
+ }
+
+ return nn
+}
+
+// heapmoves generates code to handle migrating heap-escaped parameters
+// between the stack and the heap. The generated code is added to Curfn's
+// Enter and Exit lists.
+func heapmoves() {
+ lno := lineno
+ lineno = Curfn.Pos
+ nn := paramstoheap(Curfn.Type.Recvs())
+ nn = append(nn, paramstoheap(Curfn.Type.Params())...)
+ nn = append(nn, paramstoheap(Curfn.Type.Results())...)
+ Curfn.Func.Enter.Append(nn...)
+ lineno = Curfn.Func.Endlineno
+ Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
+ lineno = lno
+}
+
+func vmkcall(fn *Node, t *types.Type, init *Nodes, va []*Node) *Node {
+ if fn.Type == nil || fn.Type.Etype != TFUNC {
+ Fatalf("mkcall %v %v", fn, fn.Type)
+ }
+
+ n := fn.Type.NumParams()
+ if n != len(va) {
+ Fatalf("vmkcall %v needs %v args got %v", fn, n, len(va))
+ }
+
+ r := nod(OCALL, fn, nil)
+ r.List.Set(va)
+ if fn.Type.NumResults() > 0 {
+ r = typecheck(r, ctxExpr|ctxMultiOK)
+ } else {
+ r = typecheck(r, ctxStmt)
+ }
+ r = walkexpr(r, init)
+ r.Type = t
+ return r
+}
+
+func mkcall(name string, t *types.Type, init *Nodes, args ...*Node) *Node {
+ return vmkcall(syslook(name), t, init, args)
+}
+
+func mkcall1(fn *Node, t *types.Type, init *Nodes, args ...*Node) *Node {
+ return vmkcall(fn, t, init, args)
+}
+
+func conv(n *Node, t *types.Type) *Node {
+ if types.Identical(n.Type, t) {
+ return n
+ }
+ n = nod(OCONV, n, nil)
+ n.Type = t
+ n = typecheck(n, ctxExpr)
+ return n
+}
+
+// convnop converts node n to type t using the OCONVNOP op
+// and typechecks the result with ctxExpr.
+func convnop(n *Node, t *types.Type) *Node {
+ if types.Identical(n.Type, t) {
+ return n
+ }
+ n = nod(OCONVNOP, n, nil)
+ n.Type = t
+ n = typecheck(n, ctxExpr)
+ return n
+}
+
+// byteindex converts n, which is byte-sized, to an int used to index into an array.
+// We cannot use conv, because we allow converting bool to int here,
+// which is forbidden in user code.
+func byteindex(n *Node) *Node {
+ // We cannot convert from bool to int directly.
+ // While converting from int8 to int is possible, it would yield
+ // the wrong result for negative values.
+ // Reinterpreting the value as an unsigned byte solves both cases.
+ if !types.Identical(n.Type, types.Types[TUINT8]) {
+ n = nod(OCONV, n, nil)
+ n.Type = types.Types[TUINT8]
+ n.SetTypecheck(1)
+ }
+ n = nod(OCONV, n, nil)
+ n.Type = types.Types[TINT]
+ n.SetTypecheck(1)
+ return n
+}
+
+func chanfn(name string, n int, t *types.Type) *Node {
+ if !t.IsChan() {
+ Fatalf("chanfn %v", t)
+ }
+ fn := syslook(name)
+ switch n {
+ default:
+ Fatalf("chanfn %d", n)
+ case 1:
+ fn = substArgTypes(fn, t.Elem())
+ case 2:
+ fn = substArgTypes(fn, t.Elem(), t.Elem())
+ }
+ return fn
+}
+
+func mapfn(name string, t *types.Type) *Node {
+ if !t.IsMap() {
+ Fatalf("mapfn %v", t)
+ }
+ fn := syslook(name)
+ fn = substArgTypes(fn, t.Key(), t.Elem(), t.Key(), t.Elem())
+ return fn
+}
+
+func mapfndel(name string, t *types.Type) *Node {
+ if !t.IsMap() {
+ Fatalf("mapfn %v", t)
+ }
+ fn := syslook(name)
+ fn = substArgTypes(fn, t.Key(), t.Elem(), t.Key())
+ return fn
+}
+
+const (
+ mapslow = iota
+ mapfast32
+ mapfast32ptr
+ mapfast64
+ mapfast64ptr
+ mapfaststr
+ nmapfast
+)
+
+type mapnames [nmapfast]string
+
+func mkmapnames(base string, ptr string) mapnames {
+ return mapnames{base, base + "_fast32", base + "_fast32" + ptr, base + "_fast64", base + "_fast64" + ptr, base + "_faststr"}
+}
+
+var mapaccess1 = mkmapnames("mapaccess1", "")
+var mapaccess2 = mkmapnames("mapaccess2", "")
+var mapassign = mkmapnames("mapassign", "ptr")
+var mapdelete = mkmapnames("mapdelete", "")
+
+func mapfast(t *types.Type) int {
+ // Check runtime/map.go:maxElemSize before changing.
+ if t.Elem().Width > 128 {
+ return mapslow
+ }
+ switch algtype(t.Key()) {
+ case AMEM32:
+ if !t.Key().HasPointers() {
+ return mapfast32
+ }
+ if Widthptr == 4 {
+ return mapfast32ptr
+ }
+ Fatalf("small pointer %v", t.Key())
+ case AMEM64:
+ if !t.Key().HasPointers() {
+ return mapfast64
+ }
+ if Widthptr == 8 {
+ return mapfast64ptr
+ }
+ // Two-word object, at least one of which is a pointer.
+ // Use the slow path.
+ case ASTRING:
+ return mapfaststr
+ }
+ return mapslow
+}
+
+func writebarrierfn(name string, l *types.Type, r *types.Type) *Node {
+ fn := syslook(name)
+ fn = substArgTypes(fn, l, r)
+ return fn
+}
+
+func addstr(n *Node, init *Nodes) *Node {
+ // order.expr rewrote OADDSTR to have a list of strings.
+ c := n.List.Len()
+
+ if c < 2 {
+ Fatalf("addstr count %d too small", c)
+ }
+
+ buf := nodnil()
+ if n.Esc == EscNone {
+ sz := int64(0)
+ for _, n1 := range n.List.Slice() {
+ if n1.Op == OLITERAL {
+ sz += int64(len(n1.StringVal()))
+ }
+ }
+
+ // Don't allocate the buffer if the result won't fit.
+ if sz < tmpstringbufsize {
+ // Create temporary buffer for result string on stack.
+ t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
+ buf = nod(OADDR, temp(t), nil)
+ }
+ }
+
+ // build list of string arguments
+ args := []*Node{buf}
+ for _, n2 := range n.List.Slice() {
+ args = append(args, conv(n2, types.Types[TSTRING]))
+ }
+
+ var fn string
+ if c <= 5 {
+ // small numbers of strings use direct runtime helpers.
+ // note: order.expr knows this cutoff too.
+ fn = fmt.Sprintf("concatstring%d", c)
+ } else {
+ // large numbers of strings are passed to the runtime as a slice.
+ fn = "concatstrings"
+
+ t := types.NewSlice(types.Types[TSTRING])
+ slice := nod(OCOMPLIT, nil, typenod(t))
+ if prealloc[n] != nil {
+ prealloc[slice] = prealloc[n]
+ }
+ slice.List.Set(args[1:]) // skip buf arg
+ args = []*Node{buf, slice}
+ slice.Esc = EscNone
+ }
+
+ cat := syslook(fn)
+ r := nod(OCALL, cat, nil)
+ r.List.Set(args)
+ r = typecheck(r, ctxExpr)
+ r = walkexpr(r, init)
+ r.Type = n.Type
+
+ return r
+}
+
+func walkAppendArgs(n *Node, init *Nodes) {
+ walkexprlistsafe(n.List.Slice(), init)
+
+ // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+ // and n are name or literal, but those may index the slice we're
+ // modifying here. Fix explicitly.
+ ls := n.List.Slice()
+ for i1, n1 := range ls {
+ ls[i1] = cheapexpr(n1, init)
+ }
+}
+
+// expand append(l1, l2...) to
+// init {
+// s := l1
+// n := len(s) + len(l2)
+// // Compare as uint so growslice can panic on overflow.
+// if uint(n) > uint(cap(s)) {
+// s = growslice(s, n)
+// }
+// s = s[:n]
+// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
+// }
+// s
+//
+// l2 is allowed to be a string.
+func appendslice(n *Node, init *Nodes) *Node {
+ walkAppendArgs(n, init)
+
+ l1 := n.List.First()
+ l2 := n.List.Second()
+ l2 = cheapexpr(l2, init)
+ n.List.SetSecond(l2)
+
+ var nodes Nodes
+
+ // var s []T
+ s := temp(l1.Type)
+ nodes.Append(nod(OAS, s, l1)) // s = l1
+
+ elemtype := s.Type.Elem()
+
+ // n := len(s) + len(l2)
+ nn := temp(types.Types[TINT])
+ nodes.Append(nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), nod(OLEN, l2, nil))))
+
+ // if uint(n) > uint(cap(s))
+ nif := nod(OIF, nil, nil)
+ nuint := conv(nn, types.Types[TUINT])
+ scapuint := conv(nod(OCAP, s, nil), types.Types[TUINT])
+ nif.Left = nod(OGT, nuint, scapuint)
+
+ // instantiate growslice(typ *type, []any, int) []any
+ fn := syslook("growslice")
+ fn = substArgTypes(fn, elemtype, elemtype)
+
+ // s = growslice(T, s, n)
+ nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn)))
+ nodes.Append(nif)
+
+ // s = s[:n]
+ nt := nod(OSLICE, s, nil)
+ nt.SetSliceBounds(nil, nn, nil)
+ nt.SetBounded(true)
+ nodes.Append(nod(OAS, s, nt))
+
+ var ncopy *Node
+ if elemtype.HasPointers() {
+ // copy(s[len(l1):], l2)
+ nptr1 := nod(OSLICE, s, nil)
+ nptr1.Type = s.Type
+ nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
+ nptr1 = cheapexpr(nptr1, &nodes)
+
+ nptr2 := l2
+
+ Curfn.Func.setWBPos(n.Pos)
+
+ // instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
+ fn := syslook("typedslicecopy")
+ fn = substArgTypes(fn, l1.Type.Elem(), l2.Type.Elem())
+ ptr1, len1 := nptr1.backingArrayPtrLen()
+ ptr2, len2 := nptr2.backingArrayPtrLen()
+ ncopy = mkcall1(fn, types.Types[TINT], &nodes, typename(elemtype), ptr1, len1, ptr2, len2)
+ } else if instrumenting && !compiling_runtime {
+ // rely on runtime to instrument:
+ // copy(s[len(l1):], l2)
+ // l2 can be a slice or string.
+ nptr1 := nod(OSLICE, s, nil)
+ nptr1.Type = s.Type
+ nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
+ nptr1 = cheapexpr(nptr1, &nodes)
+ nptr2 := l2
+
+ ptr1, len1 := nptr1.backingArrayPtrLen()
+ ptr2, len2 := nptr2.backingArrayPtrLen()
+
+ fn := syslook("slicecopy")
+ fn = substArgTypes(fn, ptr1.Type.Elem(), ptr2.Type.Elem())
+ ncopy = mkcall1(fn, types.Types[TINT], &nodes, ptr1, len1, ptr2, len2, nodintconst(elemtype.Width))
+ } else {
+ // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
+ nptr1 := nod(OINDEX, s, nod(OLEN, l1, nil))
+ nptr1.SetBounded(true)
+ nptr1 = nod(OADDR, nptr1, nil)
+
+ nptr2 := nod(OSPTR, l2, nil)
+
+ nwid := cheapexpr(conv(nod(OLEN, l2, nil), types.Types[TUINTPTR]), &nodes)
+ nwid = nod(OMUL, nwid, nodintconst(elemtype.Width))
+
+ // instantiate func memmove(to *any, frm *any, length uintptr)
+ fn := syslook("memmove")
+ fn = substArgTypes(fn, elemtype, elemtype)
+ ncopy = mkcall1(fn, nil, &nodes, nptr1, nptr2, nwid)
+ }
+ ln := append(nodes.Slice(), ncopy)
+
+ typecheckslice(ln, ctxStmt)
+ walkstmtlist(ln)
+ init.Append(ln...)
+ return s
+}
+
+// isAppendOfMake reports whether n is of the form append(x , make([]T, y)...).
+// isAppendOfMake assumes n has already been typechecked.
+func isAppendOfMake(n *Node) bool {
+ if Debug.N != 0 || instrumenting {
+ return false
+ }
+
+ if n.Typecheck() == 0 {
+ Fatalf("missing typecheck: %+v", n)
+ }
+
+ if n.Op != OAPPEND || !n.IsDDD() || n.List.Len() != 2 {
+ return false
+ }
+
+ second := n.List.Second()
+ if second.Op != OMAKESLICE || second.Right != nil {
+ return false
+ }
+
+ // y must be either an integer constant or the largest possible positive value
+ // of variable y needs to fit into an uint.
+
+ // typecheck made sure that constant arguments to make are not negative and fit into an int.
+
+ // The care of overflow of the len argument to make will be handled by an explicit check of int(len) < 0 during runtime.
+ y := second.Left
+ if !Isconst(y, CTINT) && maxintval[y.Type.Etype].Cmp(maxintval[TUINT]) > 0 {
+ return false
+ }
+
+ return true
+}
+
+// extendslice rewrites append(l1, make([]T, l2)...) to
+// init {
+// if l2 >= 0 { // Empty if block here for more meaningful node.SetLikely(true)
+// } else {
+// panicmakeslicelen()
+// }
+// s := l1
+// n := len(s) + l2
+// // Compare n and s as uint so growslice can panic on overflow of len(s) + l2.
+// // cap is a positive int and n can become negative when len(s) + l2
+// // overflows int. Interpreting n when negative as uint makes it larger
+// // than cap(s). growslice will check the int n arg and panic if n is
+// // negative. This prevents the overflow from being undetected.
+// if uint(n) > uint(cap(s)) {
+// s = growslice(T, s, n)
+// }
+// s = s[:n]
+// lptr := &l1[0]
+// sptr := &s[0]
+// if lptr == sptr || !T.HasPointers() {
+// // growslice did not clear the whole underlying array (or did not get called)
+// hp := &s[len(l1)]
+// hn := l2 * sizeof(T)
+// memclr(hp, hn)
+// }
+// }
+// s
+func extendslice(n *Node, init *Nodes) *Node {
+ // isAppendOfMake made sure all possible positive values of l2 fit into an uint.
+ // The case of l2 overflow when converting from e.g. uint to int is handled by an explicit
+ // check of l2 < 0 at runtime which is generated below.
+ l2 := conv(n.List.Second().Left, types.Types[TINT])
+ l2 = typecheck(l2, ctxExpr)
+ n.List.SetSecond(l2) // walkAppendArgs expects l2 in n.List.Second().
+
+ walkAppendArgs(n, init)
+
+ l1 := n.List.First()
+ l2 = n.List.Second() // re-read l2, as it may have been updated by walkAppendArgs
+
+ var nodes []*Node
+
+ // if l2 >= 0 (likely happens), do nothing
+ nifneg := nod(OIF, nod(OGE, l2, nodintconst(0)), nil)
+ nifneg.SetLikely(true)
+
+ // else panicmakeslicelen()
+ nifneg.Rlist.Set1(mkcall("panicmakeslicelen", nil, init))
+ nodes = append(nodes, nifneg)
+
+ // s := l1
+ s := temp(l1.Type)
+ nodes = append(nodes, nod(OAS, s, l1))
+
+ elemtype := s.Type.Elem()
+
+ // n := len(s) + l2
+ nn := temp(types.Types[TINT])
+ nodes = append(nodes, nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), l2)))
+
+ // if uint(n) > uint(cap(s))
+ nuint := conv(nn, types.Types[TUINT])
+ capuint := conv(nod(OCAP, s, nil), types.Types[TUINT])
+ nif := nod(OIF, nod(OGT, nuint, capuint), nil)
+
+ // instantiate growslice(typ *type, old []any, newcap int) []any
+ fn := syslook("growslice")
+ fn = substArgTypes(fn, elemtype, elemtype)
+
+ // s = growslice(T, s, n)
+ nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn)))
+ nodes = append(nodes, nif)
+
+ // s = s[:n]
+ nt := nod(OSLICE, s, nil)
+ nt.SetSliceBounds(nil, nn, nil)
+ nt.SetBounded(true)
+ nodes = append(nodes, nod(OAS, s, nt))
+
+ // lptr := &l1[0]
+ l1ptr := temp(l1.Type.Elem().PtrTo())
+ tmp := nod(OSPTR, l1, nil)
+ nodes = append(nodes, nod(OAS, l1ptr, tmp))
+
+ // sptr := &s[0]
+ sptr := temp(elemtype.PtrTo())
+ tmp = nod(OSPTR, s, nil)
+ nodes = append(nodes, nod(OAS, sptr, tmp))
+
+ // hp := &s[len(l1)]
+ hp := nod(OINDEX, s, nod(OLEN, l1, nil))
+ hp.SetBounded(true)
+ hp = nod(OADDR, hp, nil)
+ hp = convnop(hp, types.Types[TUNSAFEPTR])
+
+ // hn := l2 * sizeof(elem(s))
+ hn := nod(OMUL, l2, nodintconst(elemtype.Width))
+ hn = conv(hn, types.Types[TUINTPTR])
+
+ clrname := "memclrNoHeapPointers"
+ hasPointers := elemtype.HasPointers()
+ if hasPointers {
+ clrname = "memclrHasPointers"
+ Curfn.Func.setWBPos(n.Pos)
+ }
+
+ var clr Nodes
+ clrfn := mkcall(clrname, nil, &clr, hp, hn)
+ clr.Append(clrfn)
+
+ if hasPointers {
+ // if l1ptr == sptr
+ nifclr := nod(OIF, nod(OEQ, l1ptr, sptr), nil)
+ nifclr.Nbody = clr
+ nodes = append(nodes, nifclr)
+ } else {
+ nodes = append(nodes, clr.Slice()...)
+ }
+
+ typecheckslice(nodes, ctxStmt)
+ walkstmtlist(nodes)
+ init.Append(nodes...)
+ return s
+}
+
+// Rewrite append(src, x, y, z) so that any side effects in
+// x, y, z (including runtime panics) are evaluated in
+// initialization statements before the append.
+// For normal code generation, stop there and leave the
+// rest to cgen_append.
+//
+// For race detector, expand append(src, a [, b]* ) to
+//
+// init {
+// s := src
+// const argc = len(args) - 1
+// if cap(s) - len(s) < argc {
+// s = growslice(s, len(s)+argc)
+// }
+// n := len(s)
+// s = s[:n+argc]
+// s[n] = a
+// s[n+1] = b
+// ...
+// }
+// s
+func walkappend(n *Node, init *Nodes, dst *Node) *Node {
+ if !samesafeexpr(dst, n.List.First()) {
+ n.List.SetFirst(safeexpr(n.List.First(), init))
+ n.List.SetFirst(walkexpr(n.List.First(), init))
+ }
+ walkexprlistsafe(n.List.Slice()[1:], init)
+
+ nsrc := n.List.First()
+
+ // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+ // and n are name or literal, but those may index the slice we're
+ // modifying here. Fix explicitly.
+ // Using cheapexpr also makes sure that the evaluation
+ // of all arguments (and especially any panics) happen
+ // before we begin to modify the slice in a visible way.
+ ls := n.List.Slice()[1:]
+ for i, n := range ls {
+ n = cheapexpr(n, init)
+ if !types.Identical(n.Type, nsrc.Type.Elem()) {
+ n = assignconv(n, nsrc.Type.Elem(), "append")
+ n = walkexpr(n, init)
+ }
+ ls[i] = n
+ }
+
+ argc := n.List.Len() - 1
+ if argc < 1 {
+ return nsrc
+ }
+
+ // General case, with no function calls left as arguments.
+ // Leave for gen, except that instrumentation requires old form.
+ if !instrumenting || compiling_runtime {
+ return n
+ }
+
+ var l []*Node
+
+ ns := temp(nsrc.Type)
+ l = append(l, nod(OAS, ns, nsrc)) // s = src
+
+ na := nodintconst(int64(argc)) // const argc
+ nx := nod(OIF, nil, nil) // if cap(s) - len(s) < argc
+ nx.Left = nod(OLT, nod(OSUB, nod(OCAP, ns, nil), nod(OLEN, ns, nil)), na)
+
+ fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
+ fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
+
+ nx.Nbody.Set1(nod(OAS, ns,
+ mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
+ nod(OADD, nod(OLEN, ns, nil), na))))
+
+ l = append(l, nx)
+
+ nn := temp(types.Types[TINT])
+ l = append(l, nod(OAS, nn, nod(OLEN, ns, nil))) // n = len(s)
+
+ nx = nod(OSLICE, ns, nil) // ...s[:n+argc]
+ nx.SetSliceBounds(nil, nod(OADD, nn, na), nil)
+ nx.SetBounded(true)
+ 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.SetBounded(true)
+ l = append(l, nod(OAS, nx, n)) // s[n] = arg
+ if i+1 < len(ls) {
+ l = append(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))) // n = n + 1
+ }
+ }
+
+ typecheckslice(l, ctxStmt)
+ walkstmtlist(l)
+ init.Append(l...)
+ return ns
+}
+
+// Lower copy(a, b) to a memmove call or a runtime call.
+//
+// init {
+// n := len(a)
+// if n > len(b) { n = len(b) }
+// if a.ptr != b.ptr { memmove(a.ptr, b.ptr, n*sizeof(elem(a))) }
+// }
+// n;
+//
+// Also works if b is a string.
+//
+func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
+ if n.Left.Type.Elem().HasPointers() {
+ Curfn.Func.setWBPos(n.Pos)
+ fn := writebarrierfn("typedslicecopy", n.Left.Type.Elem(), n.Right.Type.Elem())
+ n.Left = cheapexpr(n.Left, init)
+ ptrL, lenL := n.Left.backingArrayPtrLen()
+ n.Right = cheapexpr(n.Right, init)
+ ptrR, lenR := n.Right.backingArrayPtrLen()
+ return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), ptrL, lenL, ptrR, lenR)
+ }
+
+ if runtimecall {
+ // rely on runtime to instrument:
+ // copy(n.Left, n.Right)
+ // n.Right can be a slice or string.
+
+ n.Left = cheapexpr(n.Left, init)
+ ptrL, lenL := n.Left.backingArrayPtrLen()
+ n.Right = cheapexpr(n.Right, init)
+ ptrR, lenR := n.Right.backingArrayPtrLen()
+
+ fn := syslook("slicecopy")
+ fn = substArgTypes(fn, ptrL.Type.Elem(), ptrR.Type.Elem())
+
+ return mkcall1(fn, n.Type, init, ptrL, lenL, ptrR, lenR, nodintconst(n.Left.Type.Elem().Width))
+ }
+
+ n.Left = walkexpr(n.Left, init)
+ n.Right = walkexpr(n.Right, init)
+ 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))
+
+ nfrm := nod(OSPTR, nr, nil)
+ nto := nod(OSPTR, nl, nil)
+
+ nlen := temp(types.Types[TINT])
+
+ // n = len(to)
+ l = append(l, nod(OAS, nlen, nod(OLEN, nl, nil)))
+
+ // if n > len(frm) { n = len(frm) }
+ nif := nod(OIF, nil, nil)
+
+ nif.Left = nod(OGT, nlen, nod(OLEN, nr, nil))
+ nif.Nbody.Append(nod(OAS, nlen, nod(OLEN, nr, nil)))
+ l = append(l, nif)
+
+ // if to.ptr != frm.ptr { memmove( ... ) }
+ ne := nod(OIF, nod(ONE, nto, nfrm), nil)
+ ne.SetLikely(true)
+ l = append(l, ne)
+
+ fn := syslook("memmove")
+ fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
+ nwid := temp(types.Types[TUINTPTR])
+ setwid := nod(OAS, nwid, conv(nlen, types.Types[TUINTPTR]))
+ ne.Nbody.Append(setwid)
+ nwid = nod(OMUL, nwid, nodintconst(nl.Type.Elem().Width))
+ call := mkcall1(fn, nil, init, nto, nfrm, nwid)
+ ne.Nbody.Append(call)
+
+ typecheckslice(l, ctxStmt)
+ walkstmtlist(l)
+ init.Append(l...)
+ return nlen
+}
+
+func eqfor(t *types.Type) (n *Node, needsize bool) {
+ // Should only arrive here with large memory or
+ // a struct/array containing a non-memory field/element.
+ // Small memory is handled inline, and single non-memory
+ // is handled by walkcompare.
+ switch a, _ := algtype1(t); a {
+ case AMEM:
+ n := syslook("memequal")
+ n = substArgTypes(n, t, t)
+ return n, true
+ case ASPECIAL:
+ sym := typesymprefix(".eq", t)
+ n := newname(sym)
+ setNodeNameFunc(n)
+ n.Type = functype(nil, []*Node{
+ anonfield(types.NewPtr(t)),
+ anonfield(types.NewPtr(t)),
+ }, []*Node{
+ anonfield(types.Types[TBOOL]),
+ })
+ return n, false
+ }
+ Fatalf("eqfor %v", t)
+ return nil, false
+}
+
+// The result of walkcompare MUST be assigned back to n, e.g.
+// n.Left = walkcompare(n.Left, init)
+func walkcompare(n *Node, init *Nodes) *Node {
+ if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != OLITERAL && n.Right.Op != OLITERAL {
+ return walkcompareInterface(n, init)
+ }
+
+ if n.Left.Type.IsString() && n.Right.Type.IsString() {
+ return walkcompareString(n, init)
+ }
+
+ n.Left = walkexpr(n.Left, init)
+ n.Right = walkexpr(n.Right, init)
+
+ // Given mixed interface/concrete comparison,
+ // rewrite into types-equal && data-equal.
+ // This is efficient, avoids allocations, and avoids runtime calls.
+ if n.Left.Type.IsInterface() != n.Right.Type.IsInterface() {
+ // Preserve side-effects in case of short-circuiting; see #32187.
+ l := cheapexpr(n.Left, init)
+ r := cheapexpr(n.Right, init)
+ // Swap so that l is the interface value and r is the concrete value.
+ if n.Right.Type.IsInterface() {
+ l, r = r, l
+ }
+
+ // Handle both == and !=.
+ eq := n.Op
+ andor := OOROR
+ if eq == OEQ {
+ andor = OANDAND
+ }
+ // 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 = types.NewPtr(types.Types[TUINT8])
+ tab.SetTypecheck(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(n.Pos, 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
+
+ maxcmpsize := int64(4)
+ unalignedLoad := canMergeLoads()
+ if unalignedLoad {
+ // Keep this low enough to generate less code than a function call.
+ maxcmpsize = 2 * int64(thearch.LinkArch.RegSize)
+ }
+
+ switch t.Etype {
+ default:
+ if Debug_libfuzzer != 0 && t.IsInteger() {
+ n.Left = cheapexpr(n.Left, init)
+ n.Right = cheapexpr(n.Right, init)
+
+ // If exactly one comparison operand is
+ // constant, invoke the constcmp functions
+ // instead, and arrange for the constant
+ // operand to be the first argument.
+ l, r := n.Left, n.Right
+ if r.Op == OLITERAL {
+ l, r = r, l
+ }
+ constcmp := l.Op == OLITERAL && r.Op != OLITERAL
+
+ var fn string
+ var paramType *types.Type
+ switch t.Size() {
+ case 1:
+ fn = "libfuzzerTraceCmp1"
+ if constcmp {
+ fn = "libfuzzerTraceConstCmp1"
+ }
+ paramType = types.Types[TUINT8]
+ case 2:
+ fn = "libfuzzerTraceCmp2"
+ if constcmp {
+ fn = "libfuzzerTraceConstCmp2"
+ }
+ paramType = types.Types[TUINT16]
+ case 4:
+ fn = "libfuzzerTraceCmp4"
+ if constcmp {
+ fn = "libfuzzerTraceConstCmp4"
+ }
+ paramType = types.Types[TUINT32]
+ case 8:
+ fn = "libfuzzerTraceCmp8"
+ if constcmp {
+ fn = "libfuzzerTraceConstCmp8"
+ }
+ paramType = types.Types[TUINT64]
+ default:
+ Fatalf("unexpected integer size %d for %v", t.Size(), t)
+ }
+ init.Append(mkcall(fn, nil, init, tracecmpArg(l, paramType, init), tracecmpArg(r, paramType, init)))
+ }
+ return n
+ case TARRAY:
+ // We can compare several elements at once with 2/4/8 byte integer compares
+ inline = t.NumElem() <= 1 || (issimple[t.Elem().Etype] && (t.NumElem() <= 4 || t.Elem().Width*t.NumElem() <= maxcmpsize))
+ case TSTRUCT:
+ inline = t.NumComponents(types.IgnoreBlankFields) <= 4
+ }
+
+ cmpl := n.Left
+ for cmpl != nil && cmpl.Op == OCONVNOP {
+ cmpl = cmpl.Left
+ }
+ cmpr := n.Right
+ for cmpr != nil && cmpr.Op == OCONVNOP {
+ cmpr = cmpr.Left
+ }
+
+ // Chose not to inline. Call equality function directly.
+ if !inline {
+ // eq algs take pointers; cmpl and cmpr must be addressable
+ if !islvalue(cmpl) || !islvalue(cmpr) {
+ Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
+ }
+
+ fn, needsize := eqfor(t)
+ call := nod(OCALL, fn, nil)
+ call.List.Append(nod(OADDR, cmpl, nil))
+ call.List.Append(nod(OADDR, cmpr, nil))
+ if needsize {
+ call.List.Append(nodintconst(t.Width))
+ }
+ res := call
+ if n.Op != OEQ {
+ res = nod(ONOT, res, nil)
+ }
+ n = finishcompare(n, res, init)
+ return n
+ }
+
+ // inline: build boolean expression comparing element by element
+ andor := OANDAND
+ if n.Op == ONE {
+ andor = OOROR
+ }
+ var expr *Node
+ compare := func(el, er *Node) {
+ a := nod(n.Op, el, er)
+ if expr == nil {
+ expr = a
+ } else {
+ expr = nod(andor, expr, a)
+ }
+ }
+ cmpl = safeexpr(cmpl, init)
+ cmpr = safeexpr(cmpr, init)
+ if t.IsStruct() {
+ for _, f := range t.Fields().Slice() {
+ sym := f.Sym
+ if sym.IsBlank() {
+ continue
+ }
+ compare(
+ nodSym(OXDOT, cmpl, sym),
+ nodSym(OXDOT, cmpr, sym),
+ )
+ }
+ } else {
+ step := int64(1)
+ remains := t.NumElem() * t.Elem().Width
+ combine64bit := unalignedLoad && Widthreg == 8 && t.Elem().Width <= 4 && t.Elem().IsInteger()
+ combine32bit := unalignedLoad && t.Elem().Width <= 2 && t.Elem().IsInteger()
+ combine16bit := unalignedLoad && t.Elem().Width == 1 && t.Elem().IsInteger()
+ for i := int64(0); remains > 0; {
+ var convType *types.Type
+ switch {
+ case remains >= 8 && combine64bit:
+ convType = types.Types[TINT64]
+ step = 8 / t.Elem().Width
+ case remains >= 4 && combine32bit:
+ convType = types.Types[TUINT32]
+ step = 4 / t.Elem().Width
+ case remains >= 2 && combine16bit:
+ convType = types.Types[TUINT16]
+ step = 2 / t.Elem().Width
+ default:
+ step = 1
+ }
+ if step == 1 {
+ compare(
+ nod(OINDEX, cmpl, nodintconst(i)),
+ nod(OINDEX, cmpr, nodintconst(i)),
+ )
+ i++
+ remains -= t.Elem().Width
+ } else {
+ elemType := t.Elem().ToUnsigned()
+ cmplw := nod(OINDEX, cmpl, nodintconst(i))
+ cmplw = conv(cmplw, elemType) // convert to unsigned
+ cmplw = conv(cmplw, convType) // widen
+ cmprw := nod(OINDEX, cmpr, nodintconst(i))
+ cmprw = conv(cmprw, elemType)
+ cmprw = conv(cmprw, convType)
+ // For code like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
+ // ssa will generate a single large load.
+ for offset := int64(1); offset < step; offset++ {
+ lb := nod(OINDEX, cmpl, nodintconst(i+offset))
+ lb = conv(lb, elemType)
+ lb = conv(lb, convType)
+ lb = nod(OLSH, lb, nodintconst(8*t.Elem().Width*offset))
+ cmplw = nod(OOR, cmplw, lb)
+ rb := nod(OINDEX, cmpr, nodintconst(i+offset))
+ rb = conv(rb, elemType)
+ rb = conv(rb, convType)
+ rb = nod(OLSH, rb, nodintconst(8*t.Elem().Width*offset))
+ cmprw = nod(OOR, cmprw, rb)
+ }
+ compare(cmplw, cmprw)
+ i += step
+ remains -= step * t.Elem().Width
+ }
+ }
+ }
+ if expr == nil {
+ expr = nodbool(n.Op == OEQ)
+ // We still need to use cmpl and cmpr, in case they contain
+ // an expression which might panic. See issue 23837.
+ t := temp(cmpl.Type)
+ a1 := nod(OAS, t, cmpl)
+ a1 = typecheck(a1, ctxStmt)
+ a2 := nod(OAS, t, cmpr)
+ a2 = typecheck(a2, ctxStmt)
+ init.Append(a1, a2)
+ }
+ n = finishcompare(n, expr, init)
+ return n
+}
+
+func tracecmpArg(n *Node, t *types.Type, init *Nodes) *Node {
+ // Ugly hack to avoid "constant -1 overflows uintptr" errors, etc.
+ if n.Op == OLITERAL && n.Type.IsSigned() && n.Int64Val() < 0 {
+ n = copyexpr(n, n.Type, init)
+ }
+
+ return conv(n, t)
+}
+
+func walkcompareInterface(n *Node, init *Nodes) *Node {
+ n.Right = cheapexpr(n.Right, init)
+ n.Left = cheapexpr(n.Left, init)
+ eqtab, eqdata := eqinterface(n.Left, n.Right)
+ var cmp *Node
+ if n.Op == OEQ {
+ cmp = nod(OANDAND, eqtab, eqdata)
+ } else {
+ eqtab.Op = ONE
+ cmp = nod(OOROR, eqtab, nod(ONOT, eqdata, nil))
+ }
+ return finishcompare(n, cmp, init)
+}
+
+func walkcompareString(n *Node, init *Nodes) *Node {
+ // 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 := n.Op
+ // Our comparison below assumes that the non-constant string
+ // is on the left hand side, so rewrite "" cmp x to x cmp "".
+ // See issue 24817.
+ if Isconst(n.Left, CTSTR) {
+ cmp = brrev(cmp)
+ }
+
+ // 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
+ // Some architectures can load unaligned byte sequence as 1 word.
+ // So we can cover longer strings with the same amount of code.
+ canCombineLoads := canMergeLoads()
+ combine64bit := false
+ if canCombineLoads {
+ // Keep this low enough to generate less code than a function call.
+ maxRewriteLen = 2 * thearch.LinkArch.RegSize
+ combine64bit = thearch.LinkArch.RegSize >= 8
+ }
+
+ 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.StringVal(); len(s) <= maxRewriteLen {
+ if len(s) > 0 {
+ ncs = safeexpr(ncs, init)
+ }
+ r := nod(cmp, nod(OLEN, ncs, nil), nodintconst(int64(len(s))))
+ remains := len(s)
+ for i := 0; remains > 0; {
+ if remains == 1 || !canCombineLoads {
+ cb := nodintconst(int64(s[i]))
+ ncb := nod(OINDEX, ncs, nodintconst(int64(i)))
+ r = nod(and, r, nod(cmp, ncb, cb))
+ remains--
+ i++
+ continue
+ }
+ var step int
+ var convType *types.Type
+ switch {
+ case remains >= 8 && combine64bit:
+ convType = types.Types[TINT64]
+ step = 8
+ case remains >= 4:
+ convType = types.Types[TUINT32]
+ step = 4
+ case remains >= 2:
+ convType = types.Types[TUINT16]
+ step = 2
+ }
+ ncsubstr := nod(OINDEX, ncs, nodintconst(int64(i)))
+ ncsubstr = conv(ncsubstr, convType)
+ csubstr := int64(s[i])
+ // Calculate large constant from bytes as sequence of shifts and ors.
+ // Like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
+ // ssa will combine this into a single large load.
+ for offset := 1; offset < step; offset++ {
+ b := nod(OINDEX, ncs, nodintconst(int64(i+offset)))
+ b = conv(b, convType)
+ b = nod(OLSH, b, nodintconst(int64(8*offset)))
+ ncsubstr = nod(OOR, ncsubstr, b)
+ csubstr |= int64(s[i+offset]) << uint8(8*offset)
+ }
+ csubstrPart := nodintconst(csubstr)
+ // Compare "step" bytes as once
+ r = nod(and, r, nod(cmp, csubstrPart, ncsubstr))
+ remains -= step
+ i += step
+ }
+ return finishcompare(n, r, init)
+ }
+ }
+
+ var r *Node
+ if n.Op == OEQ || n.Op == ONE {
+ // prepare for rewrite below
+ n.Left = cheapexpr(n.Left, init)
+ n.Right = cheapexpr(n.Right, init)
+ eqlen, eqmem := eqstring(n.Left, n.Right)
+ // quick check of len before full compare for == or !=.
+ // memequal then tests equality up to length len.
+ if n.Op == OEQ {
+ // len(left) == len(right) && memequal(left, right, len)
+ r = nod(OANDAND, eqlen, eqmem)
+ } else {
+ // len(left) != len(right) || !memequal(left, right, len)
+ eqlen.Op = ONE
+ r = nod(OOROR, eqlen, nod(ONOT, eqmem, nil))
+ }
+ } else {
+ // sys_cmpstring(s1, s2) :: 0
+ r = mkcall("cmpstring", types.Types[TINT], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING]))
+ r = nod(n.Op, r, nodintconst(0))
+ }
+
+ return finishcompare(n, r, init)
+}
+
+// The result of finishcompare MUST be assigned back to n, e.g.
+// n.Left = finishcompare(n.Left, x, r, init)
+func finishcompare(n, r *Node, init *Nodes) *Node {
+ r = typecheck(r, ctxExpr)
+ r = conv(r, n.Type)
+ r = walkexpr(r, init)
+ return r
+}
+
+// return 1 if integer n must be in range [0, max), 0 otherwise
+func bounded(n *Node, max int64) bool {
+ if n.Type == nil || !n.Type.IsInteger() {
+ return false
+ }
+
+ sign := n.Type.IsSigned()
+ bits := int32(8 * n.Type.Width)
+
+ if smallintconst(n) {
+ v := n.Int64Val()
+ return 0 <= v && v < max
+ }
+
+ switch n.Op {
+ case OAND, OANDNOT:
+ v := int64(-1)
+ switch {
+ case smallintconst(n.Left):
+ v = n.Left.Int64Val()
+ case smallintconst(n.Right):
+ v = n.Right.Int64Val()
+ if n.Op == OANDNOT {
+ v = ^v
+ if !sign {
+ v &= 1<<uint(bits) - 1
+ }
+ }
+ }
+ if 0 <= v && v < max {
+ return true
+ }
+
+ case OMOD:
+ if !sign && smallintconst(n.Right) {
+ v := n.Right.Int64Val()
+ if 0 <= v && v <= max {
+ return true
+ }
+ }
+
+ case ODIV:
+ if !sign && smallintconst(n.Right) {
+ v := n.Right.Int64Val()
+ for bits > 0 && v >= 2 {
+ bits--
+ v >>= 1
+ }
+ }
+
+ case ORSH:
+ if !sign && smallintconst(n.Right) {
+ v := n.Right.Int64Val()
+ if v > int64(bits) {
+ return true
+ }
+ bits -= int32(v)
+ }
+ }
+
+ if !sign && bits <= 62 && 1<<uint(bits) <= max {
+ return true
+ }
+
+ return false
+}
+
+// usemethod checks interface method calls for uses of reflect.Type.Method.
+func usemethod(n *Node) {
+ t := n.Left.Type
+
+ // Looking for either of:
+ // Method(int) reflect.Method
+ // MethodByName(string) (reflect.Method, bool)
+ //
+ // TODO(crawshaw): improve precision of match by working out
+ // how to check the method name.
+ if n := t.NumParams(); n != 1 {
+ return
+ }
+ if n := t.NumResults(); n != 1 && n != 2 {
+ return
+ }
+ p0 := t.Params().Field(0)
+ res0 := t.Results().Field(0)
+ var res1 *types.Field
+ if t.NumResults() == 2 {
+ res1 = t.Results().Field(1)
+ }
+
+ if res1 == nil {
+ if p0.Type.Etype != TINT {
+ return
+ }
+ } else {
+ if !p0.Type.IsString() {
+ return
+ }
+ if !res1.Type.IsBoolean() {
+ return
+ }
+ }
+
+ // Don't mark reflect.(*rtype).Method, etc. themselves in the reflect package.
+ // Those functions may be alive via the itab, which should not cause all methods
+ // alive. We only want to mark their callers.
+ if myimportpath == "reflect" {
+ switch Curfn.Func.Nname.Sym.Name { // TODO: is there a better way than hardcoding the names?
+ case "(*rtype).Method", "(*rtype).MethodByName", "(*interfaceType).Method", "(*interfaceType).MethodByName":
+ return
+ }
+ }
+
+ // Note: Don't rely on res0.Type.String() since its formatting depends on multiple factors
+ // (including global variables such as numImports - was issue #19028).
+ // Also need to check for reflect package itself (see Issue #38515).
+ if s := res0.Type.Sym; s != nil && s.Name == "Method" && isReflectPkg(s.Pkg) {
+ Curfn.Func.SetReflectMethod(true)
+ // The LSym is initialized at this point. We need to set the attribute on the LSym.
+ Curfn.Func.lsym.Set(obj.AttrReflectMethod, true)
+ }
+}
+
+func usefield(n *Node) {
+ if objabi.Fieldtrack_enabled == 0 {
+ return
+ }
+
+ switch n.Op {
+ default:
+ Fatalf("usefield %v", n.Op)
+
+ case ODOT, ODOTPTR:
+ break
+ }
+ if n.Sym == nil {
+ // No field name. This DOTPTR was built by the compiler for access
+ // to runtime data structures. Ignore.
+ return
+ }
+
+ t := n.Left.Type
+ if t.IsPtr() {
+ t = t.Elem()
+ }
+ field := n.Opt().(*types.Field)
+ if field == nil {
+ Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
+ }
+ if field.Sym != n.Sym || field.Offset != n.Xoffset {
+ Fatalf("field inconsistency: %v,%v != %v,%v", field.Sym, field.Offset, n.Sym, n.Xoffset)
+ }
+ if !strings.Contains(field.Note, "go:\"track\"") {
+ return
+ }
+
+ outer := n.Left.Type
+ if outer.IsPtr() {
+ outer = outer.Elem()
+ }
+ if outer.Sym == nil {
+ yyerror("tracked field must be in named struct type")
+ }
+ if !types.IsExported(field.Sym.Name) {
+ yyerror("tracked field must be exported (upper case)")
+ }
+
+ sym := tracksym(outer, field)
+ if Curfn.Func.FieldTrack == nil {
+ Curfn.Func.FieldTrack = make(map[*types.Sym]struct{})
+ }
+ Curfn.Func.FieldTrack[sym] = struct{}{}
+}
+
+func candiscardlist(l Nodes) bool {
+ for _, n := range l.Slice() {
+ if !candiscard(n) {
+ return false
+ }
+ }
+ return true
+}
+
+func candiscard(n *Node) bool {
+ if n == nil {
+ return true
+ }
+
+ switch n.Op {
+ default:
+ return false
+
+ // Discardable as long as the subpieces are.
+ case ONAME,
+ ONONAME,
+ OTYPE,
+ OPACK,
+ OLITERAL,
+ OADD,
+ OSUB,
+ OOR,
+ OXOR,
+ OADDSTR,
+ OADDR,
+ OANDAND,
+ OBYTES2STR,
+ ORUNES2STR,
+ OSTR2BYTES,
+ OSTR2RUNES,
+ OCAP,
+ OCOMPLIT,
+ OMAPLIT,
+ OSTRUCTLIT,
+ OARRAYLIT,
+ OSLICELIT,
+ OPTRLIT,
+ OCONV,
+ OCONVIFACE,
+ OCONVNOP,
+ ODOT,
+ OEQ,
+ ONE,
+ OLT,
+ OLE,
+ OGT,
+ OGE,
+ OKEY,
+ OSTRUCTKEY,
+ OLEN,
+ OMUL,
+ OLSH,
+ ORSH,
+ OAND,
+ OANDNOT,
+ ONEW,
+ ONOT,
+ OBITNOT,
+ OPLUS,
+ ONEG,
+ OOROR,
+ OPAREN,
+ ORUNESTR,
+ OREAL,
+ OIMAG,
+ OCOMPLEX:
+ break
+
+ // Discardable as long as we know it's not division by zero.
+ case ODIV, OMOD:
+ if Isconst(n.Right, CTINT) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 {
+ break
+ }
+ if Isconst(n.Right, CTFLT) && n.Right.Val().U.(*Mpflt).CmpFloat64(0) != 0 {
+ break
+ }
+ return false
+
+ // Discardable as long as we know it won't fail because of a bad size.
+ case OMAKECHAN, OMAKEMAP:
+ if Isconst(n.Left, CTINT) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 {
+ break
+ }
+ return false
+
+ // Difficult to tell what sizes are okay.
+ case OMAKESLICE:
+ return false
+
+ case OMAKESLICECOPY:
+ return false
+ }
+
+ if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {
+ return false
+ }
+
+ return true
+}
+
+// Rewrite
+// go builtin(x, y, z)
+// into
+// go func(a1, a2, a3) {
+// builtin(a1, a2, a3)
+// }(x, y, z)
+// for print, println, and delete.
+//
+// Rewrite
+// go f(x, y, uintptr(unsafe.Pointer(z)))
+// into
+// go func(a1, a2, a3) {
+// builtin(a1, a2, uintptr(a3))
+// }(x, y, unsafe.Pointer(z))
+// for function contains unsafe-uintptr arguments.
+
+var wrapCall_prgen int
+
+// The result of wrapCall MUST be assigned back to n, e.g.
+// n.Left = wrapCall(n.Left, init)
+func wrapCall(n *Node, init *Nodes) *Node {
+ if n.Ninit.Len() != 0 {
+ walkstmtlist(n.Ninit.Slice())
+ init.AppendNodes(&n.Ninit)
+ }
+
+ isBuiltinCall := n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER
+
+ // Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
+ if !isBuiltinCall && n.IsDDD() {
+ last := n.List.Len() - 1
+ if va := n.List.Index(last); va.Op == OSLICELIT {
+ n.List.Set(append(n.List.Slice()[:last], va.List.Slice()...))
+ n.SetIsDDD(false)
+ }
+ }
+
+ wrapArgs := n.List.Slice()
+ // If there's a receiver argument, it needs to be passed through the wrapper too.
+ if n.Op == OCALLMETH || n.Op == OCALLINTER {
+ recv := n.Left.Left
+ wrapArgs = append([]*Node{recv}, wrapArgs...)
+ }
+
+ // origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
+ origArgs := make([]*Node, len(wrapArgs))
+ t := nod(OTFUNC, nil, nil)
+ for i, arg := range wrapArgs {
+ s := lookupN("a", i)
+ if !isBuiltinCall && arg.Op == OCONVNOP && arg.Type.IsUintptr() && arg.Left.Type.IsUnsafePtr() {
+ origArgs[i] = arg
+ arg = arg.Left
+ wrapArgs[i] = arg
+ }
+ t.List.Append(symfield(s, arg.Type))
+ }
+
+ wrapCall_prgen++
+ sym := lookupN("wrap·", wrapCall_prgen)
+ fn := dclfunc(sym, t)
+
+ args := paramNnames(t.Type)
+ for i, origArg := range origArgs {
+ if origArg == nil {
+ continue
+ }
+ arg := nod(origArg.Op, args[i], nil)
+ arg.Type = origArg.Type
+ args[i] = arg
+ }
+ if n.Op == OCALLMETH || n.Op == OCALLINTER {
+ // Move wrapped receiver argument back to its appropriate place.
+ recv := typecheck(args[0], ctxExpr)
+ n.Left.Left = recv
+ args = args[1:]
+ }
+ call := nod(n.Op, nil, nil)
+ if !isBuiltinCall {
+ call.Op = OCALL
+ call.Left = n.Left
+ call.SetIsDDD(n.IsDDD())
+ }
+ call.List.Set(args)
+ fn.Nbody.Set1(call)
+
+ funcbody()
+
+ fn = typecheck(fn, ctxStmt)
+ typecheckslice(fn.Nbody.Slice(), ctxStmt)
+ xtop = append(xtop, fn)
+
+ call = nod(OCALL, nil, nil)
+ call.Left = fn.Func.Nname
+ call.List.Set(wrapArgs)
+ call = typecheck(call, ctxStmt)
+ call = walkexpr(call, init)
+ return call
+}
+
+// substArgTypes substitutes the given list of types for
+// successive occurrences of the "any" placeholder in the
+// type syntax expression n.Type.
+// The result of substArgTypes MUST be assigned back to old, e.g.
+// n.Left = substArgTypes(n.Left, t1, t2)
+func substArgTypes(old *Node, types_ ...*types.Type) *Node {
+ n := old.copy()
+
+ for _, t := range types_ {
+ dowidth(t)
+ }
+ n.Type = types.SubstAny(n.Type, &types_)
+ if len(types_) > 0 {
+ Fatalf("substArgTypes: too many argument types")
+ }
+ return n
+}
+
+// canMergeLoads reports whether the backend optimization passes for
+// the current architecture can combine adjacent loads into a single
+// larger, possibly unaligned, load. Note that currently the
+// optimizations must be able to handle little endian byte order.
+func canMergeLoads() bool {
+ switch thearch.LinkArch.Family {
+ case sys.ARM64, sys.AMD64, sys.I386, sys.S390X:
+ return true
+ case sys.PPC64:
+ // Load combining only supported on ppc64le.
+ return thearch.LinkArch.ByteOrder == binary.LittleEndian
+ }
+ return false
+}
+
+// isRuneCount reports whether n is of the form len([]rune(string)).
+// These are optimized into a call to runtime.countrunes.
+func isRuneCount(n *Node) bool {
+ return Debug.N == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES
+}
+
+func walkCheckPtrAlignment(n *Node, init *Nodes, count *Node) *Node {
+ if !n.Type.IsPtr() {
+ Fatalf("expected pointer type: %v", n.Type)
+ }
+ elem := n.Type.Elem()
+ if count != nil {
+ if !elem.IsArray() {
+ Fatalf("expected array type: %v", elem)
+ }
+ elem = elem.Elem()
+ }
+
+ size := elem.Size()
+ if elem.Alignment() == 1 && (size == 0 || size == 1 && count == nil) {
+ return n
+ }
+
+ if count == nil {
+ count = nodintconst(1)
+ }
+
+ n.Left = cheapexpr(n.Left, init)
+ init.Append(mkcall("checkptrAlignment", nil, init, convnop(n.Left, types.Types[TUNSAFEPTR]), typename(elem), conv(count, types.Types[TUINTPTR])))
+ return n
+}
+
+var walkCheckPtrArithmeticMarker byte
+
+func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
+ // Calling cheapexpr(n, init) below leads to a recursive call
+ // to walkexpr, which leads us back here again. Use n.Opt to
+ // prevent infinite loops.
+ if opt := n.Opt(); opt == &walkCheckPtrArithmeticMarker {
+ return n
+ } else if opt != nil {
+ // We use n.Opt() here because today it's not used for OCONVNOP. If that changes,
+ // there's no guarantee that temporarily replacing it is safe, so just hard fail here.
+ Fatalf("unexpected Opt: %v", opt)
+ }
+ n.SetOpt(&walkCheckPtrArithmeticMarker)
+ defer n.SetOpt(nil)
+
+ // TODO(mdempsky): Make stricter. We only need to exempt
+ // reflect.Value.Pointer and reflect.Value.UnsafeAddr.
+ switch n.Left.Op {
+ case OCALLFUNC, OCALLMETH, OCALLINTER:
+ return n
+ }
+
+ if n.Left.Op == ODOTPTR && isReflectHeaderDataField(n.Left) {
+ return n
+ }
+
+ // Find original unsafe.Pointer operands involved in this
+ // arithmetic expression.
+ //
+ // "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."
+ var originals []*Node
+ var walk func(n *Node)
+ walk = func(n *Node) {
+ switch n.Op {
+ case OADD:
+ walk(n.Left)
+ walk(n.Right)
+ case OSUB, OANDNOT:
+ walk(n.Left)
+ case OCONVNOP:
+ if n.Left.Type.IsUnsafePtr() {
+ n.Left = cheapexpr(n.Left, init)
+ originals = append(originals, convnop(n.Left, types.Types[TUNSAFEPTR]))
+ }
+ }
+ }
+ walk(n.Left)
+
+ n = cheapexpr(n, init)
+
+ slice := mkdotargslice(types.NewSlice(types.Types[TUNSAFEPTR]), originals)
+ slice.Esc = EscNone
+
+ init.Append(mkcall("checkptrArithmetic", nil, init, convnop(n, types.Types[TUNSAFEPTR]), slice))
+ // TODO(khr): Mark backing store of slice as dead. This will allow us to reuse
+ // the backing store for multiple calls to checkptrArithmetic.
+
+ return n
+}
+
+// checkPtr reports whether pointer checking should be enabled for
+// function fn at a given level. See debugHelpFooter for defined
+// levels.
+func checkPtr(fn *Node, level int) bool {
+ return Debug_checkptr >= level && fn.Func.Pragma&NoCheckPtr == 0
+}
diff --git a/src/cmd/compile/internal/gc/zerorange_test.go b/src/cmd/compile/internal/gc/zerorange_test.go
new file mode 100644
index 0000000..89f4cb9
--- /dev/null
+++ b/src/cmd/compile/internal/gc/zerorange_test.go
@@ -0,0 +1,98 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "testing"
+)
+
+var glob = 3
+var globp *int64
+
+// Testing compilation of arch.ZeroRange of various sizes.
+
+// By storing a pointer to an int64 output param in a global, the compiler must
+// ensure that output param is allocated on the heap. Also, since there is a
+// defer, the pointer to each output param must be zeroed in the prologue (see
+// plive.go:epilogue()). So, we will get a block of one or more stack slots that
+// need to be zeroed. Hence, we are testing compilation completes successfully when
+// zerorange calls of various sizes (8-136 bytes) are generated. We are not
+// testing runtime correctness (which is hard to do for the current uses of
+// ZeroRange).
+
+func TestZeroRange(t *testing.T) {
+ testZeroRange8(t)
+ testZeroRange16(t)
+ testZeroRange32(t)
+ testZeroRange64(t)
+ testZeroRange136(t)
+}
+
+func testZeroRange8(t *testing.T) (r int64) {
+ defer func() {
+ glob = 4
+ }()
+ globp = &r
+ return
+}
+
+func testZeroRange16(t *testing.T) (r, s int64) {
+ defer func() {
+ glob = 4
+ }()
+ globp = &r
+ globp = &s
+ return
+}
+
+func testZeroRange32(t *testing.T) (r, s, t2, u int64) {
+ defer func() {
+ glob = 4
+ }()
+ globp = &r
+ globp = &s
+ globp = &t2
+ globp = &u
+ return
+}
+
+func testZeroRange64(t *testing.T) (r, s, t2, u, v, w, x, y int64) {
+ defer func() {
+ glob = 4
+ }()
+ globp = &r
+ globp = &s
+ globp = &t2
+ globp = &u
+ globp = &v
+ globp = &w
+ globp = &x
+ globp = &y
+ return
+}
+
+func testZeroRange136(t *testing.T) (r, s, t2, u, v, w, x, y, r1, s1, t1, u1, v1, w1, x1, y1, z1 int64) {
+ defer func() {
+ glob = 4
+ }()
+ globp = &r
+ globp = &s
+ globp = &t2
+ globp = &u
+ globp = &v
+ globp = &w
+ globp = &x
+ globp = &y
+ globp = &r1
+ globp = &s1
+ globp = &t1
+ globp = &u1
+ globp = &v1
+ globp = &w1
+ globp = &x1
+ globp = &y1
+ globp = &z1
+ return
+}