diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:23:18 +0000 |
commit | 43a123c1ae6613b3efeed291fa552ecd909d3acf (patch) | |
tree | fd92518b7024bc74031f78a1cf9e454b65e73665 /src/cmd/compile/internal/test/testdata/gen | |
parent | Initial commit. (diff) | |
download | golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.tar.xz golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.zip |
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cmd/compile/internal/test/testdata/gen')
6 files changed, 1370 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/test/testdata/gen/arithBoundaryGen.go b/src/cmd/compile/internal/test/testdata/gen/arithBoundaryGen.go new file mode 100644 index 0000000..b03c105 --- /dev/null +++ b/src/cmd/compile/internal/test/testdata/gen/arithBoundaryGen.go @@ -0,0 +1,208 @@ +// Copyright 2015 The Go 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" + "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 = os.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/test/testdata/gen/arithConstGen.go b/src/cmd/compile/internal/test/testdata/gen/arithConstGen.go new file mode 100644 index 0000000..1649f46 --- /dev/null +++ b/src/cmd/compile/internal/test/testdata/gen/arithConstGen.go @@ -0,0 +1,345 @@ +// Copyright 2016 The Go 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" + "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 = os.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/test/testdata/gen/cmpConstGen.go b/src/cmd/compile/internal/test/testdata/gen/cmpConstGen.go new file mode 100644 index 0000000..dcdafc0 --- /dev/null +++ b/src/cmd/compile/internal/test/testdata/gen/cmpConstGen.go @@ -0,0 +1,246 @@ +// Copyright 2017 The Go 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" + "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 = os.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/test/testdata/gen/constFoldGen.go b/src/cmd/compile/internal/test/testdata/gen/constFoldGen.go new file mode 100644 index 0000000..7079422 --- /dev/null +++ b/src/cmd/compile/internal/test/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" + "log" + "os" +) + +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 = os.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/test/testdata/gen/copyGen.go b/src/cmd/compile/internal/test/testdata/gen/copyGen.go new file mode 100644 index 0000000..dd09b3b --- /dev/null +++ b/src/cmd/compile/internal/test/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" + "log" + "os" +) + +// 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 = os.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/test/testdata/gen/zeroGen.go b/src/cmd/compile/internal/test/testdata/gen/zeroGen.go new file mode 100644 index 0000000..f3dcaa1 --- /dev/null +++ b/src/cmd/compile/internal/test/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" + "log" + "os" +) + +// 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 = os.WriteFile("../zero_test.go", src, 0666) + if err != nil { + log.Fatalf("can't write output: %v\n", err) + } +} |