From fb1f47a77c642f36fc7a80d468ad1cda8bb66361 Mon Sep 17 00:00:00 2001 From: Lorenzo Masini Date: Mon, 20 Feb 2017 17:17:28 +0100 Subject: [PATCH] cmd/compile: speed up TestAssembly TestAssembly was very slow, leading to it being skipped by default. This is not surprising, it separately invoked the compiler and parsed the result many times. Now the test assembles one source file for arch/os combination, containing the relevant functions. Tests for each arch/os run in parallel. Now the test runs approximately 10x faster on my Intel(R) Core(TM) i5-6600 CPU @ 3.30GHz. Fixes #18966 Change-Id: I45ab97630b627a32e17900c109f790eb4c0e90d9 Reviewed-on: https://go-review.googlesource.com/37270 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/asm_test.go | 1059 +++++++++++++---------- 1 file changed, 590 insertions(+), 469 deletions(-) diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go index fafb8a6b04..b0e4f2fbc0 100644 --- a/src/cmd/compile/internal/gc/asm_test.go +++ b/src/cmd/compile/internal/gc/asm_test.go @@ -21,9 +21,6 @@ import ( // TestAssembly checks to make sure the assembly generated for // functions contains certain expected instructions. func TestAssembly(t *testing.T) { - if testing.Short() { - t.Skip("slow test; skipping") - } testenv.MustHaveGoBuild(t) if runtime.GOOS == "windows" { // TODO: remove if we can get "go tool compile -S" to work on windows. @@ -35,568 +32,692 @@ func TestAssembly(t *testing.T) { } defer os.RemoveAll(dir) - for _, test := range asmTests { - asm := compileToAsm(t, dir, test.arch, test.os, fmt.Sprintf(template, test.function)) - // Get rid of code for "".init. Also gets rid of type algorithms & other junk. - if i := strings.Index(asm, "\n\"\".init "); i >= 0 { - asm = asm[:i+1] + t.Run("platform", func(t *testing.T) { + for _, ats := range allAsmTests { + ats := ats + t.Run(ats.os+"/"+ats.arch, func(tt *testing.T) { + tt.Parallel() + + asm := ats.compileToAsm(tt, dir) + + for i, at := range ats.tests { + fa := funcAsm(asm, i) + + at.verifyAsm(tt, fa) + } + }) } - for _, r := range test.regexps { - if b, err := regexp.MatchString(r, asm); !b || err != nil { - t.Errorf("%s/%s: expected:%s\ngo:%s\nasm:%s\n", test.os, test.arch, r, test.function, asm) - } - } - } + }) } -// compile compiles the package pkg for architecture arch and -// returns the generated assembly. dir is a scratch directory. -func compileToAsm(t *testing.T, dir, goarch, goos, pkg string) string { - // Create source. - src := filepath.Join(dir, "test.go") - f, err := os.Create(src) - if err != nil { - panic(err) - } - f.Write([]byte(pkg)) - f.Close() - - // First, install any dependencies we need. This builds the required export data - // for any packages that are imported. - // TODO: extract dependencies automatically? - var stdout, stderr bytes.Buffer - cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", filepath.Join(dir, "encoding/binary.a"), "encoding/binary") - cmd.Env = mergeEnvLists([]string{"GOARCH=" + goarch, "GOOS=" + goos}, os.Environ()) - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - panic(err) - } - if s := stdout.String(); s != "" { - panic(fmt.Errorf("Stdout = %s\nWant empty", s)) - } - if s := stderr.String(); s != "" { - panic(fmt.Errorf("Stderr = %s\nWant empty", s)) +// funcAsm returns the assembly listing for f{funcIndex} +func funcAsm(asm string, funcIndex int) string { + if i := strings.Index(asm, fmt.Sprintf("TEXT\t\"\".f%d(SB)", funcIndex)); i >= 0 { + asm = asm[i:] } - // Now, compile the individual file for which we want to see the generated assembly. - cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", dir, "-S", "-o", filepath.Join(dir, "out.o"), src) - cmd.Env = mergeEnvLists([]string{"GOARCH=" + goarch, "GOOS=" + goos}, os.Environ()) - cmd.Stdout = &stdout - cmd.Stderr = &stderr - if err := cmd.Run(); err != nil { - panic(err) + if i := strings.Index(asm, fmt.Sprintf("TEXT\t\"\".f%d(SB)", funcIndex+1)); i >= 0 { + asm = asm[:i+1] } - if s := stderr.String(); s != "" { - panic(fmt.Errorf("Stderr = %s\nWant empty", s)) - } - return stdout.String() + + return asm } -// template to convert a function to a full file -const template = ` -package main -%s -` - type asmTest struct { - // architecture to compile to - arch string - // os to compile to - os string - // function to compile + // function to compile, must be named fX, + // where X is this test's index in asmTests.tests. function string // regexps that must match the generated assembly regexps []string } -var asmTests = [...]asmTest{ - {"amd64", "linux", ` -func f(x int) int { - return x * 64 +func (at asmTest) verifyAsm(t *testing.T, fa string) { + for _, r := range at.regexps { + if b, err := regexp.MatchString(r, fa); !b || err != nil { + t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, at.function, fa) + } + } } -`, + +type asmTests struct { + arch string + os string + imports []string + tests []*asmTest +} + +func (ats *asmTests) generateCode() []byte { + var buf bytes.Buffer + fmt.Fprintln(&buf, "package main") + for _, s := range ats.imports { + fmt.Fprintf(&buf, "import %q\n", s) + } + + for _, t := range ats.tests { + fmt.Fprintln(&buf, t.function) + } + + return buf.Bytes() +} + +// compile compiles the package pkg for architecture arch and +// returns the generated assembly. dir is a scratch directory. +func (ats *asmTests) compileToAsm(t *testing.T, dir string) string { + // create test directory + testDir := filepath.Join(dir, fmt.Sprintf("%s_%s", ats.arch, ats.os)) + err := os.Mkdir(testDir, 0700) + if err != nil { + t.Fatalf("could not create directory: %v", err) + } + + // Create source. + src := filepath.Join(testDir, "test.go") + err = ioutil.WriteFile(src, ats.generateCode(), 0600) + if err != nil { + t.Fatalf("error writing code: %v", err) + } + + // First, install any dependencies we need. This builds the required export data + // for any packages that are imported. + for _, i := range ats.imports { + out := filepath.Join(testDir, i+".a") + + if s := ats.runGo(t, "build", "-o", out, "-gcflags=-dolinkobj", i); s != "" { + t.Fatalf("Stdout = %s\nWant empty", s) + } + } + + // Now, compile the individual file for which we want to see the generated assembly. + asm := ats.runGo(t, "tool", "compile", "-I", testDir, "-S", "-o", filepath.Join(testDir, "out.o"), src) + + // Get rid of code for "".init. Also gets rid of type algorithms & other junk. + if i := strings.Index(asm, "\n\"\".init "); i >= 0 { + asm = asm[:i+1] + } + + return asm +} + +// runGo runs go command with the given args and returns stdout string. +// go is run with GOARCH and GOOS set as ats.arch and ats.os respectively +func (ats *asmTests) runGo(t *testing.T, args ...string) string { + var stdout, stderr bytes.Buffer + cmd := exec.Command(testenv.GoToolPath(t), args...) + cmd.Env = mergeEnvLists([]string{"GOARCH=" + ats.arch, "GOOS=" + ats.os}, os.Environ()) + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + t.Fatalf("error running cmd: %v", err) + } + + if s := stderr.String(); s != "" { + t.Fatalf("Stderr = %s\nWant empty", s) + } + + return stdout.String() +} + +var allAsmTests = []*asmTests{ + { + arch: "amd64", + os: "linux", + imports: []string{"encoding/binary"}, + tests: linuxAMD64Tests, + }, + { + arch: "386", + os: "linux", + imports: []string{"encoding/binary"}, + tests: linux386Tests, + }, + { + arch: "s390x", + os: "linux", + imports: []string{"encoding/binary"}, + tests: linuxS390XTests, + }, + { + arch: "arm", + os: "linux", + tests: linuxARMTests, + }, + { + arch: "arm64", + os: "linux", + tests: linuxARM64Tests, + }, +} + +var linuxAMD64Tests = []*asmTest{ + { + ` + func f0(x int) int { + return x * 64 + } + `, []string{"\tSHLQ\t\\$6,"}, }, - {"amd64", "linux", ` -func f(x int) int { - return x * 96 -}`, + { + ` + func f1(x int) int { + return x * 96 + } + `, []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"}, }, // Load-combining tests. - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte) uint64 { - return binary.LittleEndian.Uint64(b) -} -`, + { + ` + func f2(b []byte) uint64 { + return binary.LittleEndian.Uint64(b) + } + `, []string{"\tMOVQ\t\\(.*\\),"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint64 { - return binary.LittleEndian.Uint64(b[i:]) -} -`, + { + ` + func f3(b []byte, i int) uint64 { + return binary.LittleEndian.Uint64(b[i:]) + } + `, []string{"\tMOVQ\t\\(.*\\)\\(.*\\*1\\),"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte) uint32 { - return binary.LittleEndian.Uint32(b) -} -`, + { + ` + func f4(b []byte) uint32 { + return binary.LittleEndian.Uint32(b) + } + `, []string{"\tMOVL\t\\(.*\\),"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint32 { - return binary.LittleEndian.Uint32(b[i:]) -} -`, + { + ` + func f5(b []byte, i int) uint32 { + return binary.LittleEndian.Uint32(b[i:]) + } + `, []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte) uint64 { - return binary.BigEndian.Uint64(b) -} -`, + { + ` + func f6(b []byte) uint64 { + return binary.BigEndian.Uint64(b) + } + `, []string{"\tBSWAPQ\t"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint64 { - return binary.BigEndian.Uint64(b[i:]) -} -`, + { + ` + func f7(b []byte, i int) uint64 { + return binary.BigEndian.Uint64(b[i:]) + } + `, []string{"\tBSWAPQ\t"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, v uint64) { - binary.BigEndian.PutUint64(b, v) -} -`, + { + ` + func f8(b []byte, v uint64) { + binary.BigEndian.PutUint64(b, v) + } + `, []string{"\tBSWAPQ\t"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, i int, v uint64) { - binary.BigEndian.PutUint64(b[i:], v) -} -`, + { + ` + func f9(b []byte, i int, v uint64) { + binary.BigEndian.PutUint64(b[i:], v) + } + `, []string{"\tBSWAPQ\t"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte) uint32 { - return binary.BigEndian.Uint32(b) -} -`, + { + ` + func f10(b []byte) uint32 { + return binary.BigEndian.Uint32(b) + } + `, []string{"\tBSWAPL\t"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint32 { - return binary.BigEndian.Uint32(b[i:]) -} -`, + { + ` + func f11(b []byte, i int) uint32 { + return binary.BigEndian.Uint32(b[i:]) + } + `, []string{"\tBSWAPL\t"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, v uint32) { - binary.BigEndian.PutUint32(b, v) -} -`, + { + ` + func f12(b []byte, v uint32) { + binary.BigEndian.PutUint32(b, v) + } + `, []string{"\tBSWAPL\t"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, i int, v uint32) { - binary.BigEndian.PutUint32(b[i:], v) -} -`, + { + ` + func f13(b []byte, i int, v uint32) { + binary.BigEndian.PutUint32(b[i:], v) + } + `, []string{"\tBSWAPL\t"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte) uint16 { - return binary.BigEndian.Uint16(b) -} -`, + { + ` + func f14(b []byte) uint16 { + return binary.BigEndian.Uint16(b) + } + `, []string{"\tROLW\t\\$8,"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint16 { - return binary.BigEndian.Uint16(b[i:]) -} -`, + { + ` + func f15(b []byte, i int) uint16 { + return binary.BigEndian.Uint16(b[i:]) + } + `, []string{"\tROLW\t\\$8,"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, v uint16) { - binary.BigEndian.PutUint16(b, v) -} -`, + { + ` + func f16(b []byte, v uint16) { + binary.BigEndian.PutUint16(b, v) + } + `, []string{"\tROLW\t\\$8,"}, }, - {"amd64", "linux", ` -import "encoding/binary" -func f(b []byte, i int, v uint16) { - binary.BigEndian.PutUint16(b[i:], v) -} -`, + { + ` + func f17(b []byte, i int, v uint16) { + binary.BigEndian.PutUint16(b[i:], v) + } + `, []string{"\tROLW\t\\$8,"}, }, - {"386", "linux", ` -import "encoding/binary" -func f(b []byte) uint32 { - return binary.LittleEndian.Uint32(b) -} -`, - []string{"\tMOVL\t\\(.*\\),"}, - }, - {"386", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint32 { - return binary.LittleEndian.Uint32(b[i:]) -} -`, - []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, - }, - {"s390x", "linux", ` -import "encoding/binary" -func f(b []byte) uint32 { - return binary.LittleEndian.Uint32(b) -} -`, - []string{"\tMOVWBR\t\\(.*\\),"}, - }, - {"s390x", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint32 { - return binary.LittleEndian.Uint32(b[i:]) -} -`, - []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"}, - }, - {"s390x", "linux", ` -import "encoding/binary" -func f(b []byte) uint64 { - return binary.LittleEndian.Uint64(b) -} -`, - []string{"\tMOVDBR\t\\(.*\\),"}, - }, - {"s390x", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint64 { - return binary.LittleEndian.Uint64(b[i:]) -} -`, - []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"}, - }, - {"s390x", "linux", ` -import "encoding/binary" -func f(b []byte) uint32 { - return binary.BigEndian.Uint32(b) -} -`, - []string{"\tMOVWZ\t\\(.*\\),"}, - }, - {"s390x", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint32 { - return binary.BigEndian.Uint32(b[i:]) -} -`, - []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"}, - }, - {"s390x", "linux", ` -import "encoding/binary" -func f(b []byte) uint64 { - return binary.BigEndian.Uint64(b) -} -`, - []string{"\tMOVD\t\\(.*\\),"}, - }, - {"s390x", "linux", ` -import "encoding/binary" -func f(b []byte, i int) uint64 { - return binary.BigEndian.Uint64(b[i:]) -} -`, - []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"}, - }, - // Structure zeroing. See issue #18370. - {"amd64", "linux", ` -type T struct { - a, b, c int -} -func f(t *T) { - *t = T{} -} -`, + { + ` + type T1 struct { + a, b, c int + } + func f18(t *T1) { + *t = T1{} + } + `, []string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"}, }, // TODO: add a test for *t = T{3,4,5} when we fix that. // Also test struct containing pointers (this was special because of write barriers). - {"amd64", "linux", ` -type T struct { - a, b, c *int -} -func f(t *T) { - *t = T{} -} -`, + { + ` + type T2 struct { + a, b, c *int + } + func f19(t *T2) { + *t = T2{} + } + `, []string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)", "\tCALL\truntime\\.writebarrierptr\\(SB\\)"}, }, - // Rotate tests - {"amd64", "linux", ` - func f(x uint64) uint64 { - return x<<7 | x>>57 - } -`, + { + ` + func f20(x uint64) uint64 { + return x<<7 | x>>57 + } + `, []string{"\tROLQ\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint64) uint64 { - return x<<7 + x>>57 - } -`, + { + ` + func f21(x uint64) uint64 { + return x<<7 + x>>57 + } + `, []string{"\tROLQ\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint64) uint64 { - return x<<7 ^ x>>57 - } -`, + { + ` + func f22(x uint64) uint64 { + return x<<7 ^ x>>57 + } + `, []string{"\tROLQ\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint32) uint32 { - return x<<7 + x>>25 - } -`, + { + ` + func f23(x uint32) uint32 { + return x<<7 + x>>25 + } + `, []string{"\tROLL\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint32) uint32 { - return x<<7 | x>>25 - } -`, + { + ` + func f24(x uint32) uint32 { + return x<<7 | x>>25 + } + `, []string{"\tROLL\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint32) uint32 { - return x<<7 ^ x>>25 - } -`, + { + ` + func f25(x uint32) uint32 { + return x<<7 ^ x>>25 + } + `, []string{"\tROLL\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint16) uint16 { - return x<<7 + x>>9 - } -`, + { + ` + func f26(x uint16) uint16 { + return x<<7 + x>>9 + } + `, []string{"\tROLW\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint16) uint16 { - return x<<7 | x>>9 - } -`, + { + ` + func f27(x uint16) uint16 { + return x<<7 | x>>9 + } + `, []string{"\tROLW\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint16) uint16 { - return x<<7 ^ x>>9 - } -`, + { + ` + func f28(x uint16) uint16 { + return x<<7 ^ x>>9 + } + `, []string{"\tROLW\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint8) uint8 { - return x<<7 + x>>1 - } -`, + { + ` + func f29(x uint8) uint8 { + return x<<7 + x>>1 + } + `, []string{"\tROLB\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint8) uint8 { - return x<<7 | x>>1 - } -`, + { + ` + func f30(x uint8) uint8 { + return x<<7 | x>>1 + } + `, []string{"\tROLB\t[$]7,"}, }, - {"amd64", "linux", ` - func f(x uint8) uint8 { - return x<<7 ^ x>>1 - } -`, + { + ` + func f31(x uint8) uint8 { + return x<<7 ^ x>>1 + } + `, []string{"\tROLB\t[$]7,"}, }, - - {"arm", "linux", ` - func f(x uint32) uint32 { - return x<<7 + x>>25 - } -`, - []string{"\tMOVW\tR[0-9]+@>25,"}, - }, - {"arm", "linux", ` - func f(x uint32) uint32 { - return x<<7 | x>>25 - } -`, - []string{"\tMOVW\tR[0-9]+@>25,"}, - }, - {"arm", "linux", ` - func f(x uint32) uint32 { - return x<<7 ^ x>>25 - } -`, - []string{"\tMOVW\tR[0-9]+@>25,"}, - }, - - {"arm64", "linux", ` - func f(x uint64) uint64 { - return x<<7 + x>>57 - } -`, - []string{"\tROR\t[$]57,"}, - }, - {"arm64", "linux", ` - func f(x uint64) uint64 { - return x<<7 | x>>57 - } -`, - []string{"\tROR\t[$]57,"}, - }, - {"arm64", "linux", ` - func f(x uint64) uint64 { - return x<<7 ^ x>>57 - } -`, - []string{"\tROR\t[$]57,"}, - }, - {"arm64", "linux", ` - func f(x uint32) uint32 { - return x<<7 + x>>25 - } -`, - []string{"\tRORW\t[$]25,"}, - }, - {"arm64", "linux", ` - func f(x uint32) uint32 { - return x<<7 | x>>25 - } -`, - []string{"\tRORW\t[$]25,"}, - }, - {"arm64", "linux", ` - func f(x uint32) uint32 { - return x<<7 ^ x>>25 - } -`, - []string{"\tRORW\t[$]25,"}, - }, - - {"s390x", "linux", ` - func f(x uint64) uint64 { - return x<<7 + x>>57 - } -`, - []string{"\tRLLG\t[$]7,"}, - }, - {"s390x", "linux", ` - func f(x uint64) uint64 { - return x<<7 | x>>57 - } -`, - []string{"\tRLLG\t[$]7,"}, - }, - {"s390x", "linux", ` - func f(x uint64) uint64 { - return x<<7 ^ x>>57 - } -`, - []string{"\tRLLG\t[$]7,"}, - }, - {"s390x", "linux", ` - func f(x uint32) uint32 { - return x<<7 + x>>25 - } -`, - []string{"\tRLL\t[$]7,"}, - }, - {"s390x", "linux", ` - func f(x uint32) uint32 { - return x<<7 | x>>25 - } -`, - []string{"\tRLL\t[$]7,"}, - }, - {"s390x", "linux", ` - func f(x uint32) uint32 { - return x<<7 ^ x>>25 - } -`, - []string{"\tRLL\t[$]7,"}, - }, - // Rotate after inlining (see issue 18254). - {"amd64", "linux", ` - func f(x uint32, k uint) uint32 { - return x<>(32-k) - } - func g(x uint32) uint32 { - return f(x, 7) - } -`, + { + ` + func g(x uint32, k uint) uint32 { + return x<>(32-k) + } + func f32(x uint32) uint32 { + return g(x, 7) + } + `, []string{"\tROLL\t[$]7,"}, }, - + { + ` + func f33(m map[int]int) int { + return m[5] + } + `, + []string{"\tMOVQ\t[$]5,"}, + }, // Direct use of constants in fast map access calls. Issue 19015. - {"amd64", "linux", ` - func f(m map[int]int) int { - return m[5] - } -`, + { + ` + func f34(m map[int]int) bool { + _, ok := m[5] + return ok + } + `, []string{"\tMOVQ\t[$]5,"}, }, - {"amd64", "linux", ` - func f(m map[int]int) bool { - _, ok := m[5] - return ok - } -`, - []string{"\tMOVQ\t[$]5,"}, - }, - {"amd64", "linux", ` - func f(m map[string]int) int { - return m["abc"] - } -`, + { + ` + func f35(m map[string]int) int { + return m["abc"] + } + `, []string{"\"abc\""}, }, - {"amd64", "linux", ` - func f(m map[string]int) bool { - _, ok := m["abc"] - return ok - } -`, + { + ` + func f36(m map[string]int) bool { + _, ok := m["abc"] + return ok + } + `, []string{"\"abc\""}, }, } +var linux386Tests = []*asmTest{ + { + ` + func f0(b []byte) uint32 { + return binary.LittleEndian.Uint32(b) + } + `, + []string{"\tMOVL\t\\(.*\\),"}, + }, + { + ` + func f1(b []byte, i int) uint32 { + return binary.LittleEndian.Uint32(b[i:]) + } + `, + []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"}, + }, +} + +var linuxS390XTests = []*asmTest{ + { + ` + func f0(b []byte) uint32 { + return binary.LittleEndian.Uint32(b) + } + `, + []string{"\tMOVWBR\t\\(.*\\),"}, + }, + { + ` + func f1(b []byte, i int) uint32 { + return binary.LittleEndian.Uint32(b[i:]) + } + `, + []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"}, + }, + { + ` + func f2(b []byte) uint64 { + return binary.LittleEndian.Uint64(b) + } + `, + []string{"\tMOVDBR\t\\(.*\\),"}, + }, + { + ` + func f3(b []byte, i int) uint64 { + return binary.LittleEndian.Uint64(b[i:]) + } + `, + []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"}, + }, + { + ` + func f4(b []byte) uint32 { + return binary.BigEndian.Uint32(b) + } + `, + []string{"\tMOVWZ\t\\(.*\\),"}, + }, + { + ` + func f5(b []byte, i int) uint32 { + return binary.BigEndian.Uint32(b[i:]) + } + `, + []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"}, + }, + { + ` + func f6(b []byte) uint64 { + return binary.BigEndian.Uint64(b) + } + `, + []string{"\tMOVD\t\\(.*\\),"}, + }, + { + ` + func f7(b []byte, i int) uint64 { + return binary.BigEndian.Uint64(b[i:]) + } + `, + []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"}, + }, + { + ` + func f8(x uint64) uint64 { + return x<<7 + x>>57 + } + `, + []string{"\tRLLG\t[$]7,"}, + }, + { + ` + func f9(x uint64) uint64 { + return x<<7 | x>>57 + } + `, + []string{"\tRLLG\t[$]7,"}, + }, + { + ` + func f10(x uint64) uint64 { + return x<<7 ^ x>>57 + } + `, + []string{"\tRLLG\t[$]7,"}, + }, + { + ` + func f11(x uint32) uint32 { + return x<<7 + x>>25 + } + `, + []string{"\tRLL\t[$]7,"}, + }, + { + ` + func f12(x uint32) uint32 { + return x<<7 | x>>25 + } + `, + []string{"\tRLL\t[$]7,"}, + }, + { + ` + func f13(x uint32) uint32 { + return x<<7 ^ x>>25 + } + `, + []string{"\tRLL\t[$]7,"}, + }, +} + +var linuxARMTests = []*asmTest{ + { + ` + func f0(x uint32) uint32 { + return x<<7 + x>>25 + } + `, + []string{"\tMOVW\tR[0-9]+@>25,"}, + }, + { + ` + func f1(x uint32) uint32 { + return x<<7 | x>>25 + } + `, + []string{"\tMOVW\tR[0-9]+@>25,"}, + }, + { + ` + func f2(x uint32) uint32 { + return x<<7 ^ x>>25 + } + `, + []string{"\tMOVW\tR[0-9]+@>25,"}, + }, +} + +var linuxARM64Tests = []*asmTest{ + { + ` + func f0(x uint64) uint64 { + return x<<7 + x>>57 + } + `, + []string{"\tROR\t[$]57,"}, + }, + { + ` + func f1(x uint64) uint64 { + return x<<7 | x>>57 + } + `, + []string{"\tROR\t[$]57,"}, + }, + { + ` + func f2(x uint64) uint64 { + return x<<7 ^ x>>57 + } + `, + []string{"\tROR\t[$]57,"}, + }, + { + ` + func f3(x uint32) uint32 { + return x<<7 + x>>25 + } + `, + []string{"\tRORW\t[$]25,"}, + }, + { + ` + func f4(x uint32) uint32 { + return x<<7 | x>>25 + } + `, + []string{"\tRORW\t[$]25,"}, + }, + { + ` + func f5(x uint32) uint32 { + return x<<7 ^ x>>25 + } + `, + []string{"\tRORW\t[$]25,"}, + }, +} + // mergeEnvLists merges the two environment lists such that // variables with the same name in "in" replace those in "out". // This always returns a newly allocated slice.