Commit fad31e51 authored by Giovanni Bajo's avatar Giovanni Bajo

test: move load/store combines into asmcheck

This CL moves the load/store combining tests into asmcheck.
In addition at being more compact, it's also now easier to
spot what it is missing in each architecture.

While doing so, I think I uncovered a bug in ppc64le and arm64
rules, because they fail to load/store combine in non-trivial
functions. Not sure why, I'll open an issue.

Change-Id: Ia1572d53c0553d9104f3e52b95e4d1768a8440a3
Reviewed-on: https://go-review.googlesource.com/98441
Run-TryBot: Giovanni Bajo <rasky@develer.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent 80bfb75c
......@@ -224,19 +224,19 @@ var allAsmTests = []*asmTests{
{
arch: "amd64",
os: "linux",
imports: []string{"encoding/binary", "math", "math/bits", "unsafe", "runtime"},
imports: []string{"math", "math/bits", "unsafe", "runtime"},
tests: linuxAMD64Tests,
},
{
arch: "386",
os: "linux",
imports: []string{"encoding/binary", "math"},
imports: []string{"math"},
tests: linux386Tests,
},
{
arch: "s390x",
os: "linux",
imports: []string{"encoding/binary", "math", "math/bits"},
imports: []string{"math", "math/bits"},
tests: linuxS390XTests,
},
{
......@@ -248,7 +248,7 @@ var allAsmTests = []*asmTests{
{
arch: "arm64",
os: "linux",
imports: []string{"encoding/binary", "math", "math/bits"},
imports: []string{"math", "math/bits"},
tests: linuxARM64Tests,
},
{
......@@ -266,7 +266,7 @@ var allAsmTests = []*asmTests{
{
arch: "ppc64le",
os: "linux",
imports: []string{"encoding/binary", "math", "math/bits"},
imports: []string{"math", "math/bits"},
tests: linuxPPC64LETests,
},
{
......@@ -305,183 +305,6 @@ var linuxAMD64Tests = []*asmTest{
`,
pos: []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"},
},
// Load-combining tests.
{
fn: `
func f2(b []byte) uint64 {
return binary.LittleEndian.Uint64(b)
}
`,
pos: []string{"\tMOVQ\t\\(.*\\),"},
},
{
fn: `
func f3(b []byte, i int) uint64 {
return binary.LittleEndian.Uint64(b[i:])
}
`,
pos: []string{"\tMOVQ\t\\(.*\\)\\(.*\\*1\\),"},
},
{
fn: `
func f4(b []byte) uint32 {
return binary.LittleEndian.Uint32(b)
}
`,
pos: []string{"\tMOVL\t\\(.*\\),"},
},
{
fn: `
func f5(b []byte, i int) uint32 {
return binary.LittleEndian.Uint32(b[i:])
}
`,
pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
},
{
fn: `
func $(b []byte, v uint64) {
binary.LittleEndian.PutUint64(b, v)
}
`,
neg: []string{"SHRQ"},
},
{
fn: `
func $(b []byte, i int, v uint64) {
binary.LittleEndian.PutUint64(b[i:], v)
}
`,
neg: []string{"SHRQ"},
},
{
fn: `
func $(b []byte, v uint32) {
binary.LittleEndian.PutUint32(b, v)
}
`,
neg: []string{"SHRL", "SHRQ"},
},
{
fn: `
func $(b []byte, i int, v uint32) {
binary.LittleEndian.PutUint32(b[i:], v)
}
`,
neg: []string{"SHRL", "SHRQ"},
},
{
fn: `
func $(b []byte, v uint16) {
binary.LittleEndian.PutUint16(b, v)
}
`,
neg: []string{"SHRW", "SHRL", "SHRQ"},
},
{
fn: `
func $(b []byte, i int, v uint16) {
binary.LittleEndian.PutUint16(b[i:], v)
}
`,
neg: []string{"SHRW", "SHRL", "SHRQ"},
},
{
fn: `
func f6(b []byte) uint64 {
return binary.BigEndian.Uint64(b)
}
`,
pos: []string{"\tBSWAPQ\t"},
},
{
fn: `
func f7(b []byte, i int) uint64 {
return binary.BigEndian.Uint64(b[i:])
}
`,
pos: []string{"\tBSWAPQ\t"},
},
{
fn: `
func f8(b []byte, v uint64) {
binary.BigEndian.PutUint64(b, v)
}
`,
pos: []string{"\tBSWAPQ\t"},
},
{
fn: `
func f9(b []byte, i int, v uint64) {
binary.BigEndian.PutUint64(b[i:], v)
}
`,
pos: []string{"\tBSWAPQ\t"},
},
{
fn: `
func f10(b []byte) uint32 {
return binary.BigEndian.Uint32(b)
}
`,
pos: []string{"\tBSWAPL\t"},
},
{
fn: `
func f11(b []byte, i int) uint32 {
return binary.BigEndian.Uint32(b[i:])
}
`,
pos: []string{"\tBSWAPL\t"},
},
{
fn: `
func f12(b []byte, v uint32) {
binary.BigEndian.PutUint32(b, v)
}
`,
pos: []string{"\tBSWAPL\t"},
},
{
fn: `
func f13(b []byte, i int, v uint32) {
binary.BigEndian.PutUint32(b[i:], v)
}
`,
pos: []string{"\tBSWAPL\t"},
},
{
fn: `
func f14(b []byte) uint16 {
return binary.BigEndian.Uint16(b)
}
`,
pos: []string{"\tROLW\t\\$8,"},
},
{
fn: `
func f15(b []byte, i int) uint16 {
return binary.BigEndian.Uint16(b[i:])
}
`,
pos: []string{"\tROLW\t\\$8,"},
},
{
fn: `
func f16(b []byte, v uint16) {
binary.BigEndian.PutUint16(b, v)
}
`,
pos: []string{"\tROLW\t\\$8,"},
},
{
fn: `
func f17(b []byte, i int, v uint16) {
binary.BigEndian.PutUint16(b[i:], v)
}
`,
pos: []string{"\tROLW\t\\$8,"},
},
// Structure zeroing. See issue #18370.
{
fn: `
......@@ -1336,23 +1159,6 @@ var linuxAMD64Tests = []*asmTest{
}
var linux386Tests = []*asmTest{
{
fn: `
func f0(b []byte) uint32 {
return binary.LittleEndian.Uint32(b)
}
`,
pos: []string{"\tMOVL\t\\(.*\\),"},
},
{
fn: `
func f1(b []byte, i int) uint32 {
return binary.LittleEndian.Uint32(b[i:])
}
`,
pos: []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
},
// multiplication by powers of two
{
fn: `
......@@ -1497,70 +1303,6 @@ var linux386Tests = []*asmTest{
}
var linuxS390XTests = []*asmTest{
{
fn: `
func f0(b []byte) uint32 {
return binary.LittleEndian.Uint32(b)
}
`,
pos: []string{"\tMOVWBR\t\\(.*\\),"},
},
{
fn: `
func f1(b []byte, i int) uint32 {
return binary.LittleEndian.Uint32(b[i:])
}
`,
pos: []string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"},
},
{
fn: `
func f2(b []byte) uint64 {
return binary.LittleEndian.Uint64(b)
}
`,
pos: []string{"\tMOVDBR\t\\(.*\\),"},
},
{
fn: `
func f3(b []byte, i int) uint64 {
return binary.LittleEndian.Uint64(b[i:])
}
`,
pos: []string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"},
},
{
fn: `
func f4(b []byte) uint32 {
return binary.BigEndian.Uint32(b)
}
`,
pos: []string{"\tMOVWZ\t\\(.*\\),"},
},
{
fn: `
func f5(b []byte, i int) uint32 {
return binary.BigEndian.Uint32(b[i:])
}
`,
pos: []string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"},
},
{
fn: `
func f6(b []byte) uint64 {
return binary.BigEndian.Uint64(b)
}
`,
pos: []string{"\tMOVD\t\\(.*\\),"},
},
{
fn: `
func f7(b []byte, i int) uint64 {
return binary.BigEndian.Uint64(b[i:])
}
`,
pos: []string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"},
},
{
fn: `
func f8(x uint64) uint64 {
......@@ -2388,70 +2130,6 @@ var linuxARM64Tests = []*asmTest{
pos: []string{"\tVCNT\t", "\tVUADDLV\t"},
},
// Load-combining tests.
{
fn: `
func $(b []byte) uint64 {
return binary.LittleEndian.Uint64(b)
}
`,
pos: []string{"\tMOVD\t\\(R[0-9]+\\)"},
},
{
fn: `
func $(b []byte, i int) uint64 {
return binary.LittleEndian.Uint64(b[i:])
}
`,
pos: []string{"\tMOVD\t\\(R[0-9]+\\)"},
},
{
fn: `
func $(b []byte) uint32 {
return binary.LittleEndian.Uint32(b)
}
`,
pos: []string{"\tMOVWU\t\\(R[0-9]+\\)"},
},
{
fn: `
func $(b []byte, i int) uint32 {
return binary.LittleEndian.Uint32(b[i:])
}
`,
pos: []string{"\tMOVWU\t\\(R[0-9]+\\)"},
},
{
fn: `
func $(b []byte) uint64 {
return binary.BigEndian.Uint64(b)
}
`,
pos: []string{"\tREV\t"},
},
{
fn: `
func $(b []byte, i int) uint64 {
return binary.BigEndian.Uint64(b[i:])
}
`,
pos: []string{"\tREV\t"},
},
{
fn: `
func $(b []byte) uint32 {
return binary.BigEndian.Uint32(b)
}
`,
pos: []string{"\tREVW\t"},
},
{
fn: `
func $(b []byte, i int) uint32 {
return binary.BigEndian.Uint32(b[i:])
}
`,
pos: []string{"\tREVW\t"},
},
{
fn: `
func $(s []byte) uint16 {
......@@ -2759,61 +2437,6 @@ var linuxARM64Tests = []*asmTest{
pos: []string{"STP"},
neg: []string{"MOVB", "MOVH", "MOVW"},
},
// Check that stores are combine into larger stores
{
fn: `
func $(b []byte, v uint16) {
binary.LittleEndian.PutUint16(b, v)
}
`,
pos: []string{"MOVH"},
neg: []string{"MOVB"},
},
{
fn: `
func $(b []byte, v uint32) {
binary.LittleEndian.PutUint32(b, v)
}
`,
pos: []string{"MOVW"},
neg: []string{"MOVB", "MOVH"},
},
{
fn: `
func $(b []byte, v uint64) {
binary.LittleEndian.PutUint64(b, v)
}
`,
pos: []string{"MOVD"},
neg: []string{"MOVB", "MOVH", "MOVW"},
},
{
fn: `
func $(b []byte, v uint16) {
binary.BigEndian.PutUint16(b, v)
}
`,
pos: []string{"MOVH"},
neg: []string{"MOVB"},
},
{
fn: `
func $(b []byte, v uint32) {
binary.BigEndian.PutUint32(b, v)
}
`,
pos: []string{"MOVW"},
neg: []string{"MOVB", "MOVH"},
},
{
fn: `
func $(b []byte, v uint64) {
binary.BigEndian.PutUint64(b, v)
}
`,
pos: []string{"MOVD"},
neg: []string{"MOVB", "MOVH", "MOVW"},
},
}
var linuxMIPSTests = []*asmTest{
......@@ -3058,61 +2681,6 @@ var linuxPPC64LETests = []*asmTest{
pos: []string{"\tFABS\t"},
},
{
fn: `
func f14(b []byte) uint16 {
return binary.LittleEndian.Uint16(b)
}
`,
pos: []string{"\tMOVHZ\t"},
},
{
fn: `
func f15(b []byte) uint32 {
return binary.LittleEndian.Uint32(b)
}
`,
pos: []string{"\tMOVWZ\t"},
},
{
fn: `
func f16(b []byte) uint64 {
return binary.LittleEndian.Uint64(b)
}
`,
pos: []string{"\tMOVD\t"},
neg: []string{"MOVBZ", "MOVHZ", "MOVWZ"},
},
{
fn: `
func f17(b []byte, v uint16) {
binary.LittleEndian.PutUint16(b, v)
}
`,
pos: []string{"\tMOVH\t"},
},
{
fn: `
func f18(b []byte, v uint32) {
binary.LittleEndian.PutUint32(b, v)
}
`,
pos: []string{"\tMOVW\t"},
},
{
fn: `
func f19(b []byte, v uint64) {
binary.LittleEndian.PutUint64(b, v)
}
`,
pos: []string{"\tMOVD\t"},
neg: []string{"MOVB", "MOVH", "MOVW"},
},
{
// check that stack store is optimized away
fn: `
......
// asmcheck
// Copyright 2018 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 codegen
import "encoding/binary"
var sink64 uint64
var sink32 uint32
var sink16 uint16
func load_le64(b []byte) {
// amd64:`MOVQ\s\(.*\),`
// s390x:`MOVDBR\s\(.*\),`
// arm64:`MOVD\s\(R[0-9]+\),`
// ppc64le:`MOVD\s`,-`MOV[BHW]Z`
sink64 = binary.LittleEndian.Uint64(b)
}
func load_le64_idx(b []byte, idx int) {
// amd64:`MOVQ\s\(.*\)\(.*\*1\),`
// s390x:`MOVDBR\s\(.*\)\(.*\*1\),`
// arm64:`MOVD\s\(R[0-9]+\),`
// ppc64le:`MOVD\s`,-`MOV[BHW]Z\s`
sink64 = binary.LittleEndian.Uint64(b[idx:])
}
func load_le32(b []byte) {
// amd64:`MOVL\s\(.*\),` 386:`MOVL\s\(.*\),`
// s390x:`MOVWBR\s\(.*\),`
// arm64:`MOVWU\s\(R[0-9]+\),`
// ppc64le:`MOVWZ\s`
sink32 = binary.LittleEndian.Uint32(b)
}
func load_le32_idx(b []byte, idx int) {
// amd64:`MOVL\s\(.*\)\(.*\*1\),` 386:`MOVL\s\(.*\)\(.*\*1\),`
// s390x:`MOVWBR\s\(.*\)\(.*\*1\),`
// arm64:`MOVWU\s\(R[0-9]+\),`
// ppc64le:`MOVWZ\s`
sink32 = binary.LittleEndian.Uint32(b[idx:])
}
func load_le16(b []byte) {
// amd64:`MOVWLZX\s\(.*\),`
// ppc64le:`MOVHZ\s`
sink16 = binary.LittleEndian.Uint16(b)
}
func load_le16_idx(b []byte, idx int) {
// amd64:`MOVWLZX\s\(.*\),`
// ppc64le:`MOVHZ\s`
sink16 = binary.LittleEndian.Uint16(b[idx:])
}
func load_be64(b []byte) {
// amd64:`BSWAPQ`
// s390x:`MOVD\s\(.*\),`
// arm64:`REV`
sink64 = binary.BigEndian.Uint64(b)
}
func load_be64_idx(b []byte, idx int) {
// amd64:`BSWAPQ`
// s390x:`MOVD\s\(.*\)\(.*\*1\),`
// arm64:`REV`
sink64 = binary.BigEndian.Uint64(b[idx:])
}
func load_be32(b []byte) {
// amd64:`BSWAPL`
// s390x:`MOVWZ\s\(.*\),`
// arm64:`REVW`
sink32 = binary.BigEndian.Uint32(b)
}
func load_be32_idx(b []byte, idx int) {
// amd64:`BSWAPL`
// s390x:`MOVWZ\s\(.*\)\(.*\*1\),`
// arm64:`REVW`
sink32 = binary.BigEndian.Uint32(b[idx:])
}
func load_be16(b []byte) {
// amd64:`ROLW\s\$8`
sink16 = binary.BigEndian.Uint16(b)
}
func load_be16_idx(b []byte, idx int) {
// amd64:`ROLW\s\$8`
sink16 = binary.BigEndian.Uint16(b[idx:])
}
func store_le64(b []byte) {
// amd64:`MOVQ\s.*\(.*\)$`,-`SHR.`
// arm64:`MOVD`,-`MOV[WBH]`
// ppc64le:`MOVD\s`,-`MOV[BHW]\s`
binary.LittleEndian.PutUint64(b, sink64)
}
func store_le64_idx(b []byte, idx int) {
// amd64:`MOVQ\s.*\(.*\)\(.*\*1\)$`,-`SHR.`
// arm64:`MOVD`,-`MOV[WBH]`
// ppc64le:`MOVD\s`,-`MOV[BHW]\s`
binary.LittleEndian.PutUint64(b[idx:], sink64)
}
func store_le32(b []byte) {
// amd64:`MOVL\s`
// arm64(DISABLED):`MOVW`,-`MOV[BH]`
// ppc64le:`MOVW\s`
binary.LittleEndian.PutUint32(b, sink32)
}
func store_le32_idx(b []byte, idx int) {
// amd64:`MOVL\s`
// arm64(DISABLED):`MOVW`,-`MOV[BH]`
// ppc64le:`MOVW\s`
binary.LittleEndian.PutUint32(b[idx:], sink32)
}
func store_le16(b []byte) {
// amd64:`MOVW\s`
// arm64(DISABLED):`MOVH`,-`MOVB`
// ppc64le(DISABLED):`MOVH\s`
binary.LittleEndian.PutUint16(b, sink16)
}
func store_le16_idx(b []byte, idx int) {
// amd64:`MOVW\s`
// arm64(DISABLED):`MOVH`,-`MOVB`
// ppc64le(DISABLED):`MOVH\s`
binary.LittleEndian.PutUint16(b[idx:], sink16)
}
func store_be64(b []byte) {
// amd64:`BSWAPQ`,-`SHR.`
// arm64:`MOVD`,`REV`,-`MOV[WBH]`
binary.BigEndian.PutUint64(b, sink64)
}
func store_be64_idx(b []byte, idx int) {
// amd64:`BSWAPQ`,-`SHR.`
// arm64:`MOVD`,`REV`,-`MOV[WBH]`
binary.BigEndian.PutUint64(b[idx:], sink64)
}
func store_be32(b []byte) {
// amd64:`BSWAPL`,-`SHR.`
// arm64(DISABLED):`MOVW`,`REVW`,-`MOV[BH]`
binary.BigEndian.PutUint32(b, sink32)
}
func store_be32_idx(b []byte, idx int) {
// amd64:`BSWAPL`,-`SHR.`
// arm64(DISABLED):`MOVW`,`REVW`,-`MOV[BH]`
binary.BigEndian.PutUint32(b[idx:], sink32)
}
func store_be16(b []byte) {
// amd64:`ROLW\s\$8`,-`SHR.`
// arm64(DISABLED):`MOVH`,`REV16W`,-`MOVB`
binary.BigEndian.PutUint16(b, sink16)
}
func store_be16_idx(b []byte, idx int) {
// amd64:`ROLW\s\$8`,-`SHR.`
// arm64(DISABLED):`MOVH`,`REV16W`,-`MOVB`
binary.BigEndian.PutUint16(b[idx:], sink16)
}
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