aboutsummaryrefslogtreecommitdiff
path: root/test/run.go
diff options
context:
space:
mode:
authorGiovanni Bajo <rasky@develer.com>2018-04-15 19:00:27 +0200
committerGiovanni Bajo <rasky@develer.com>2018-04-15 20:02:43 +0000
commit284ba47b4916e3cf4f206494ad5a3577e20db9bf (patch)
tree9c2ab90dc5d305c01085d088ad9a301333a86d8e /test/run.go
parent01aa1d7dbe3a5b9f9a96f84cc625cbb7e372b0f0 (diff)
downloadgo-284ba47b4916e3cf4f206494ad5a3577e20db9bf.tar.gz
go-284ba47b4916e3cf4f206494ad5a3577e20db9bf.zip
test: run codegen tests on all supported architecture variants
This CL makes the codegen testsuite automatically test all architecture variants for architecture specified in tests. For instance, if a test file specifies a "arm" test, it will be automatically run on all GOARM variants (5,6,7), to increase the coverage. The CL also introduces a syntax to specify only a specific variant (eg: "arm/7") in case the test makes sense only there. The same syntax also allows to specify the operating system in case it matters (eg: "plan9/386/sse2"). Fixes #24658 Change-Id: I2eba8b918f51bb6a77a8431a309f8b71af07ea22 Reviewed-on: https://go-review.googlesource.com/107315 Run-TryBot: Giovanni Bajo <rasky@develer.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'test/run.go')
-rw-r--r--test/run.go135
1 files changed, 104 insertions, 31 deletions
diff --git a/test/run.go b/test/run.go
index d432b67485..e80b037ca1 100644
--- a/test/run.go
+++ b/test/run.go
@@ -5,9 +5,6 @@
// license that can be found in the LICENSE file.
// Run runs tests in the test directory.
-//
-// TODO(bradfitz): docs of some sort, once we figure out how we're changing
-// headers of files
package main
import (
@@ -610,13 +607,13 @@ func (t *test) run() {
t.err = fmt.Errorf("unimplemented action %q", action)
case "asmcheck":
- ops, archs := t.wantedAsmOpcodes(long)
- for _, arch := range archs {
+ ops := t.wantedAsmOpcodes(long)
+ for _, env := range ops.Envs() {
cmdline := []string{"build", "-gcflags", "-S"}
cmdline = append(cmdline, flags...)
cmdline = append(cmdline, long)
cmd := exec.Command(goTool(), cmdline...)
- cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH="+arch, "GOARM=7")
+ cmd.Env = append(os.Environ(), env.Environ()...)
var buf bytes.Buffer
cmd.Stdout, cmd.Stderr = &buf, &buf
@@ -625,7 +622,7 @@ func (t *test) run() {
return
}
- t.err = t.asmCheck(buf.String(), long, arch, ops[arch])
+ t.err = t.asmCheck(buf.String(), long, env, ops[env])
if t.err != nil {
return
}
@@ -1289,12 +1286,28 @@ var (
// Regexp to extract an architecture check: architecture name, followed by semi-colon,
// followed by a comma-separated list of opcode checks.
- rxAsmPlatform = regexp.MustCompile(`(\w+):(` + reMatchCheck + `(?:,` + reMatchCheck + `)*)`)
+ rxAsmPlatform = regexp.MustCompile(`(\w+)(/\w+)?(/\w*)?:(` + reMatchCheck + `(?:,` + reMatchCheck + `)*)`)
// Regexp to extract a single opcoded check
rxAsmCheck = regexp.MustCompile(reMatchCheck)
+
+ // List of all architecture variants. Key is the GOARCH architecture,
+ // value[1] is the variant-changing environment variable, and values[1:]
+ // are the supported variants.
+ archVariants = map[string][]string{
+ "386": {"GO386", "387", "sse2"},
+ "amd64": {},
+ "arm": {"GOARM", "5", "6", "7"},
+ "arm64": {},
+ "mips": {"GOMIPS", "hardfloat", "softfloat"},
+ "mips64": {},
+ "ppc64": {},
+ "ppc64le": {},
+ "s390x": {},
+ }
)
+// wantedAsmOpcode is a single asmcheck check
type wantedAsmOpcode struct {
fileline string // original source file/line (eg: "/path/foo.go:45")
line int // original source line
@@ -1303,9 +1316,44 @@ type wantedAsmOpcode struct {
found bool // true if the opcode check matched at least one in the output
}
-func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpcode, []string) {
- ops := make(map[string]map[string][]wantedAsmOpcode)
- archs := make(map[string]bool)
+// A build environment triplet separated by slashes (eg: linux/386/sse2).
+// The third field can be empty if the arch does not support variants (eg: "plan9/amd64")
+type buildEnv string
+
+// Environ returns the environment it represents in cmd.Environ() "key=val" format
+// For instance, "linux/386/sse2".Environ() returns {"GOOS=linux", "GOARCH=386", "GO386=sse2"}
+func (b buildEnv) Environ() []string {
+ fields := strings.Split(string(b), "/")
+ if len(fields) != 3 && len(fields) != 2 {
+ panic("invalid buildEnv string: " + string(b))
+ }
+ env := []string{"GOOS=" + fields[0], "GOARCH=" + fields[1]}
+ if len(fields) == 3 {
+ env = append(env, archVariants[fields[1]][0]+"="+fields[2])
+ }
+ return env
+}
+
+// asmChecks represents all the asmcheck checks present in a test file
+// The outer map key is the build triplet in which the checks must be performed.
+// The inner map key represent the source file line ("filename.go:1234") at which the
+// checks must be performed.
+type asmChecks map[buildEnv]map[string][]wantedAsmOpcode
+
+// Envs returns all the buildEnv in which at least one check is present
+func (a asmChecks) Envs() []buildEnv {
+ var envs []buildEnv
+ for e := range a {
+ envs = append(envs, e)
+ }
+ sort.Slice(envs, func(i, j int) bool {
+ return string(envs[i]) < string(envs[j])
+ })
+ return envs
+}
+
+func (t *test) wantedAsmOpcodes(fn string) asmChecks {
+ ops := make(asmChecks)
comment := ""
src, _ := ioutil.ReadFile(fn)
@@ -1324,7 +1372,36 @@ func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpc
// made by one architecture name and multiple checks.
lnum := fn + ":" + strconv.Itoa(i+1)
for _, ac := range rxAsmPlatform.FindAllStringSubmatch(comment, -1) {
- arch, allchecks := ac[1], ac[2]
+ archspec, allchecks := ac[1:4], ac[4]
+
+ var arch, subarch, os string
+ switch {
+ case archspec[2] != "": // 3 components: "linux/386/sse2"
+ os, arch, subarch = archspec[0], archspec[1][1:], archspec[2][1:]
+ case archspec[1] != "": // 2 components: "386/sse2"
+ os, arch, subarch = "linux", archspec[0], archspec[1][1:]
+ default: // 1 component: "386"
+ os, arch, subarch = "linux", archspec[0], ""
+ }
+
+ if _, ok := archVariants[arch]; !ok {
+ log.Fatalf("%s:%d: unsupported architecture: %v", t.goFileName(), i+1, arch)
+ }
+
+ // Create the build environments corresponding the above specifiers
+ envs := make([]buildEnv, 0, 4)
+ if subarch != "" {
+ envs = append(envs, buildEnv(os+"/"+arch+"/"+subarch))
+ } else {
+ subarchs := archVariants[arch]
+ if len(subarchs) == 0 {
+ envs = append(envs, buildEnv(os+"/"+arch))
+ } else {
+ for _, sa := range archVariants[arch][1:] {
+ envs = append(envs, buildEnv(os+"/"+arch+"/"+sa))
+ }
+ }
+ }
for _, m := range rxAsmCheck.FindAllString(allchecks, -1) {
negative := false
@@ -1350,31 +1427,27 @@ func (t *test) wantedAsmOpcodes(fn string) (map[string]map[string][]wantedAsmOpc
if err != nil {
log.Fatalf("%s:%d: %v", t.goFileName(), i+1, err)
}
- if ops[arch] == nil {
- ops[arch] = make(map[string][]wantedAsmOpcode)
+
+ for _, env := range envs {
+ if ops[env] == nil {
+ ops[env] = make(map[string][]wantedAsmOpcode)
+ }
+ ops[env][lnum] = append(ops[env][lnum], wantedAsmOpcode{
+ negative: negative,
+ fileline: lnum,
+ line: i + 1,
+ opcode: oprx,
+ })
}
- archs[arch] = true
- ops[arch][lnum] = append(ops[arch][lnum], wantedAsmOpcode{
- negative: negative,
- fileline: lnum,
- line: i + 1,
- opcode: oprx,
- })
}
}
comment = ""
}
- var sarchs []string
- for a := range archs {
- sarchs = append(sarchs, a)
- }
- sort.Strings(sarchs)
-
- return ops, sarchs
+ return ops
}
-func (t *test) asmCheck(outStr string, fn string, arch string, fullops map[string][]wantedAsmOpcode) (err error) {
+func (t *test) asmCheck(outStr string, fn string, env buildEnv, fullops map[string][]wantedAsmOpcode) (err error) {
// The assembly output contains the concatenated dump of multiple functions.
// the first line of each function begins at column 0, while the rest is
// indented by a tabulation. These data structures help us index the
@@ -1449,9 +1522,9 @@ func (t *test) asmCheck(outStr string, fn string, arch string, fullops map[strin
}
if o.negative {
- fmt.Fprintf(&errbuf, "%s:%d: %s: wrong opcode found: %q\n", t.goFileName(), o.line, arch, o.opcode.String())
+ fmt.Fprintf(&errbuf, "%s:%d: %s: wrong opcode found: %q\n", t.goFileName(), o.line, env, o.opcode.String())
} else {
- fmt.Fprintf(&errbuf, "%s:%d: %s: opcode not found: %q\n", t.goFileName(), o.line, arch, o.opcode.String())
+ fmt.Fprintf(&errbuf, "%s:%d: %s: opcode not found: %q\n", t.goFileName(), o.line, env, o.opcode.String())
}
}
err = errors.New(errbuf.String())