Commit fb1f47a7 authored by Lorenzo Masini's avatar Lorenzo Masini Committed by Brad Fitzpatrick

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 <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 349b7820
......@@ -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,565 +32,689 @@ 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)
}
})
}
// 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:]
}
if i := strings.Index(asm, fmt.Sprintf("TEXT\t\"\".f%d(SB)", funcIndex+1)); i >= 0 {
asm = asm[:i+1]
}
return asm
}
type asmTest struct {
// 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
}
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 compileToAsm(t *testing.T, dir, goarch, goos, pkg string) string {
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(dir, "test.go")
f, err := os.Create(src)
src := filepath.Join(testDir, "test.go")
err = ioutil.WriteFile(src, ats.generateCode(), 0600)
if err != nil {
panic(err)
t.Fatalf("error writing code: %v", 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))
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.
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())
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 {
panic(err)
t.Fatalf("error running cmd: %v", err)
}
if s := stderr.String(); s != "" {
panic(fmt.Errorf("Stderr = %s\nWant empty", s))
t.Fatalf("Stderr = %s\nWant empty", s)
}
return stdout.String()
}
// 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 string
// regexps that must match the generated assembly
regexps []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 asmTests = [...]asmTest{
{"amd64", "linux", `
func f(x int) int {
return x * 64
}
`,
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,"},
// Rotate after inlining (see issue 18254).
{
`
func g(x uint32, k uint) uint32 {
return x<<k | x>>(32-k)
}
func f32(x uint32) uint32 {
return g(x, 7)
}
`,
[]string{"\tROLL\t[$]7,"},
},
{"arm", "linux", `
func f(x uint32) uint32 {
return x<<7 | x>>25
}
`,
[]string{"\tMOVW\tR[0-9]+@>25,"},
{
`
func f33(m map[int]int) int {
return m[5]
}
`,
[]string{"\tMOVQ\t[$]5,"},
},
{"arm", "linux", `
func f(x uint32) uint32 {
return x<<7 ^ x>>25
}
`,
[]string{"\tMOVW\tR[0-9]+@>25,"},
// Direct use of constants in fast map access calls. Issue 19015.
{
`
func f34(m map[int]int) bool {
_, ok := m[5]
return ok
}
`,
[]string{"\tMOVQ\t[$]5,"},
},
{
`
func f35(m map[string]int) int {
return m["abc"]
}
`,
[]string{"\"abc\""},
},
{
`
func f36(m map[string]int) bool {
_, ok := m["abc"]
return ok
}
`,
[]string{"\"abc\""},
},
}
{"arm64", "linux", `
func f(x uint64) uint64 {
return x<<7 + x>>57
}
`,
[]string{"\tROR\t[$]57,"},
var linux386Tests = []*asmTest{
{
`
func f0(b []byte) uint32 {
return binary.LittleEndian.Uint32(b)
}
`,
[]string{"\tMOVL\t\\(.*\\),"},
},
{"arm64", "linux", `
func f(x uint64) uint64 {
return x<<7 | x>>57
}
`,
[]string{"\tROR\t[$]57,"},
{
`
func f1(b []byte, i int) uint32 {
return binary.LittleEndian.Uint32(b[i:])
}
`,
[]string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
},
{"arm64", "linux", `
func f(x uint64) uint64 {
return x<<7 ^ x>>57
}
`,
[]string{"\tROR\t[$]57,"},
}
var linuxS390XTests = []*asmTest{
{
`
func f0(b []byte) uint32 {
return binary.LittleEndian.Uint32(b)
}
`,
[]string{"\tMOVWBR\t\\(.*\\),"},
},
{"arm64", "linux", `
func f(x uint32) uint32 {
return x<<7 + x>>25
}
`,
[]string{"\tRORW\t[$]25,"},
{
`
func f1(b []byte, i int) uint32 {
return binary.LittleEndian.Uint32(b[i:])
}
`,
[]string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"},
},
{"arm64", "linux", `
func f(x uint32) uint32 {
return x<<7 | x>>25
}
`,
[]string{"\tRORW\t[$]25,"},
{
`
func f2(b []byte) uint64 {
return binary.LittleEndian.Uint64(b)
}
`,
[]string{"\tMOVDBR\t\\(.*\\),"},
},
{"arm64", "linux", `
func f(x uint32) uint32 {
return x<<7 ^ x>>25
}
`,
[]string{"\tRORW\t[$]25,"},
{
`
func f3(b []byte, i int) uint64 {
return binary.LittleEndian.Uint64(b[i:])
}
`,
[]string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"},
},
{"s390x", "linux", `
func f(x uint64) uint64 {
return x<<7 + x>>57
}
`,
{
`
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,"},
},
{"s390x", "linux", `
func f(x uint64) uint64 {
return x<<7 | x>>57
}
`,
{
`
func f9(x uint64) uint64 {
return x<<7 | x>>57
}
`,
[]string{"\tRLLG\t[$]7,"},
},
{"s390x", "linux", `
func f(x uint64) uint64 {
return x<<7 ^ x>>57
}
`,
{
`
func f10(x uint64) uint64 {
return x<<7 ^ x>>57
}
`,
[]string{"\tRLLG\t[$]7,"},
},
{"s390x", "linux", `
func f(x uint32) uint32 {
return x<<7 + x>>25
}
`,
{
`
func f11(x uint32) uint32 {
return x<<7 + x>>25
}
`,
[]string{"\tRLL\t[$]7,"},
},
{"s390x", "linux", `
func f(x uint32) uint32 {
return x<<7 | x>>25
}
`,
{
`
func f12(x uint32) uint32 {
return x<<7 | x>>25
}
`,
[]string{"\tRLL\t[$]7,"},
},
{"s390x", "linux", `
func f(x uint32) uint32 {
return x<<7 ^ x>>25
}
`,
{
`
func f13(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<<k | x>>(32-k)
}
func g(x uint32) uint32 {
return f(x, 7)
}
`,
[]string{"\tROLL\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,"},
},
}
// Direct use of constants in fast map access calls. Issue 19015.
{"amd64", "linux", `
func f(m map[int]int) int {
return m[5]
}
`,
[]string{"\tMOVQ\t[$]5,"},
var linuxARM64Tests = []*asmTest{
{
`
func f0(x uint64) uint64 {
return x<<7 + x>>57
}
`,
[]string{"\tROR\t[$]57,"},
},
{"amd64", "linux", `
func f(m map[int]int) bool {
_, ok := m[5]
return ok
}
`,
[]string{"\tMOVQ\t[$]5,"},
{
`
func f1(x uint64) uint64 {
return x<<7 | x>>57
}
`,
[]string{"\tROR\t[$]57,"},
},
{"amd64", "linux", `
func f(m map[string]int) int {
return m["abc"]
}
`,
[]string{"\"abc\""},
{
`
func f2(x uint64) uint64 {
return x<<7 ^ x>>57
}
`,
[]string{"\tROR\t[$]57,"},
},
{"amd64", "linux", `
func f(m map[string]int) bool {
_, ok := m["abc"]
return ok
}
`,
[]string{"\"abc\""},
{
`
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,"},
},
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment