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.