// architecture-specific, and they are grouped in arrays of tests, one
// for each architecture.
//
-// Each asmTest consists in a function to be compiled and an array of
-// regexps that will be matched to the generated assembly. For
-// example, the following amd64 test
+// Each asmTest consists of a function to compile, an array of
+// positiveRegexps that will be matched to the generated assembly and
+// an array of negativeRegexps that must not match generated assembly.
+// For example, the following amd64 test
//
// {
// `
// }
// `,
// []string{"\tSHLQ\t[$]6,"},
+// []string{"MULQ"}
// }
//
// verifies that the code the compiler generates for a multiplication
-// by 64 contains a 'SHLQ' instruction.
+// by 64 contains a 'SHLQ' instruction and does not contain a MULQ.
//
// Since all the tests for a given architecture are dumped in the same
// file, the function names must be unique. As a workaround for this
// }
// `,
// []string{"\tSHLQ\t[$]6,"},
+// []string{"MULQ"}
// }
//
// Each '$'-function will be given a unique name of form f<N>_<arch>,
type asmTest struct {
// function to compile
function string
- // regexps that must match the generated assembly
- regexps []string
+ // positiveRegexps that must match the generated assembly
+ positiveRegexps []string
+ negativeRegexps []string
}
func (at asmTest) verifyAsm(t *testing.T, fa string) {
- for _, r := range at.regexps {
+ for _, r := range at.positiveRegexps {
if b, err := regexp.MatchString(r, fa); !b || err != nil {
t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, at.function, fa)
}
}
+ for _, r := range at.negativeRegexps {
+ if b, err := regexp.MatchString(r, fa); b || err != nil {
+ t.Errorf("not expected:%s\ngo:%s\nasm:%s\n", r, at.function, fa)
+ }
+ }
}
type asmTests struct {
{
arch: "amd64",
os: "linux",
- imports: []string{"encoding/binary", "math", "math/bits", "unsafe"},
+ imports: []string{"encoding/binary", "math", "math/bits", "unsafe", "runtime"},
tests: linuxAMD64Tests,
},
{
}
`,
[]string{"\tSHLQ\t\\$6,"},
+ []string{},
},
{
`
}
`,
[]string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"},
+ []string{},
},
// Load-combining tests.
{
}
`,
[]string{"\tMOVQ\t\\(.*\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVQ\t\\(.*\\)\\(.*\\*1\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVL\t\\(.*\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPL\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPL\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPL\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPL\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLW\t\\$8,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLW\t\\$8,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLW\t\\$8,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLW\t\\$8,"},
+ []string{},
},
// Structure zeroing. See issue #18370.
{
}
`,
[]string{"\tXORPS\tX., X", "\tMOVUPS\tX., \\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"},
+ []string{},
},
// SSA-able composite literal initialization. Issue 18872.
{
}
`,
[]string{"\tMOVQ\t[$]1", "\tMOVQ\t[$]2", "\tMOVQ\t[$]3", "\tMOVQ\t[$]4"},
+ []string{},
},
// Also test struct containing pointers (this was special because of write barriers).
{
}
`,
[]string{"\tXORPS\tX., X", "\tMOVUPS\tX., \\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)", "\tCALL\truntime\\.writebarrierptr\\(SB\\)"},
+ []string{},
},
// Rotate tests
{
}
`,
[]string{"\tROLQ\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLQ\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLQ\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLL\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLL\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLL\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLW\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLW\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLW\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLB\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLB\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLB\t[$]7,"},
+ []string{},
},
// Rotate after inlining (see issue 18254).
{
}
`,
[]string{"\tROLL\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVQ\t[$]5,"},
+ []string{},
},
// Direct use of constants in fast map access calls. Issue 19015.
{
}
`,
[]string{"\tMOVQ\t[$]5,"},
+ []string{},
},
{
`
}
`,
[]string{"\"abc\""},
+ []string{},
},
{
`
}
`,
[]string{"\"abc\""},
+ []string{},
},
// Bit test ops on amd64, issue 18943.
{
}
`,
[]string{"\tBTQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBTQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBTQ\t\\$60"},
+ []string{},
},
{
`
}
`,
[]string{"\tBTQ\t\\$60"},
+ []string{},
},
// Intrinsic tests for math/bits
{
}
`,
[]string{"\tBSFQ\t", "\tMOVL\t\\$64,", "\tCMOVQEQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSFQ\t", "\tORQ\t[^$]", "\tMOVQ\t\\$4294967296,"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSFQ\t", "\tORQ\t\\$65536,"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSFQ\t", "\tORQ\t\\$256,"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSWAPL\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tROLW\t\\$8,"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
/* see ssa.go
{
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
*/
{
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
/* see ssa.go
{
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
*/
{
}
`,
[]string{"\tBSRQ\t"},
+ []string{},
},
{
`
return bits.OnesCount64(x)
}`,
[]string{"\tPOPCNTQ\t", "support_popcnt"},
+ []string{},
},
{
`
return bits.OnesCount32(x)
}`,
[]string{"\tPOPCNTL\t", "support_popcnt"},
+ []string{},
},
{
`
return bits.OnesCount16(x)
}`,
[]string{"\tPOPCNTL\t", "support_popcnt"},
+ []string{},
},
{
`
return bits.OnesCount(x)
}`,
[]string{"\tPOPCNTQ\t", "support_popcnt"},
+ []string{},
},
// multiplication merging tests
{
return 15*n + 31*n
}`,
[]string{"\tIMULQ\t[$]46"}, // 46*n
+ []string{},
},
{
`
return 5*n + 7*(n+1) + 11*(n+2)
}`,
[]string{"\tIMULQ\t[$]23", "\tADDQ\t[$]29"}, // 23*n + 29
+ []string{},
},
{
`
return a*n + 19*n
}`,
[]string{"\tADDQ\t[$]19", "\tIMULQ"}, // (a+19)*n
+ []string{},
},
// see issue 19595.
*q += x
}`,
[]string{"\tADDQ\t\\("},
+ []string{},
},
{
`
}
}`,
[]string{"\tADDQ\t[A-Z]"},
+ []string{},
},
// Floating-point strength reduction
{
return f * 2.0
}`,
[]string{"\tADDSD\t"},
+ []string{},
},
{
`
return f / 16.0
}`,
[]string{"\tMULSD\t"},
+ []string{},
},
{
`
return f / 0.125
}`,
[]string{"\tMULSD\t"},
+ []string{},
},
{
`
return f / 0.5
}`,
[]string{"\tADDSD\t"},
+ []string{},
},
// Check that compare to constant string uses 2/4/8 byte compares
{
return a == "xx"
}`,
[]string{"\tCMPW\t[A-Z]"},
+ []string{},
},
{
`
return a == "xxxx"
}`,
[]string{"\tCMPL\t[A-Z]"},
+ []string{},
},
{
`
return a == "xxxxxxxx"
}`,
[]string{"\tCMPQ\t[A-Z]"},
+ []string{},
},
// Non-constant rotate
{
return x << z | x >> (64-z)
}`,
[]string{"\tROLQ\t"},
+ []string{},
},
{
`func rot64r(x uint64, y int) uint64 {
return x >> z | x << (64-z)
}`,
[]string{"\tRORQ\t"},
+ []string{},
},
{
`func rot32l(x uint32, y int) uint32 {
return x << z | x >> (32-z)
}`,
[]string{"\tROLL\t"},
+ []string{},
},
{
`func rot32r(x uint32, y int) uint32 {
return x >> z | x << (32-z)
}`,
[]string{"\tRORL\t"},
+ []string{},
},
{
`func rot16l(x uint16, y int) uint16 {
return x << z | x >> (16-z)
}`,
[]string{"\tROLW\t"},
+ []string{},
},
{
`func rot16r(x uint16, y int) uint16 {
return x >> z | x << (16-z)
}`,
[]string{"\tRORW\t"},
+ []string{},
},
{
`func rot8l(x uint8, y int) uint8 {
return x << z | x >> (8-z)
}`,
[]string{"\tROLB\t"},
+ []string{},
},
{
`func rot8r(x uint8, y int) uint8 {
return x >> z | x << (8-z)
}`,
[]string{"\tRORB\t"},
+ []string{},
},
// Check that array compare uses 2/4/8 byte compares
{
return a == b
}`,
[]string{"\tCMPW\t[A-Z]"},
+ []string{},
},
{
`
return a == b
}`,
[]string{"\tCMPL\t[A-Z]"},
+ []string{},
},
{
`
return a == b
}`,
[]string{"\tCMPQ\t[A-Z]"},
+ []string{},
},
{
`
return *((*[4]byte)(a)) != *((*[4]byte)(b))
}`,
[]string{"\tCMPL\t[A-Z]"},
+ []string{},
},
{
// make sure assembly output has matching offset and base register.
}
`,
[]string{"b\\+40\\(SP\\)"},
+ []string{},
+ },
+ {
+ // check load combining
+ `
+ func f73(a, b byte) (byte,byte) {
+ return f73(f73(a,b))
+ }
+ `,
+ []string{"\tMOVW\t"},
+ []string{},
+ },
+ {
+ `
+ func f74(a, b uint16) (uint16,uint16) {
+ return f74(f74(a,b))
+ }
+ `,
+ []string{"\tMOVL\t"},
+ []string{},
+ },
+ {
+ `
+ func f75(a, b uint32) (uint32,uint32) {
+ return f75(f75(a,b))
+ }
+ `,
+ []string{"\tMOVQ\t"},
+ []string{},
+ },
+ {
+ `
+ func f76(a, b uint64) (uint64,uint64) {
+ return f76(f76(a,b))
+ }
+ `,
+ []string{"\tMOVUPS\t"},
+ []string{},
+ },
+ // Make sure we don't put pointers in SSE registers across safe points.
+ {
+ `
+ func $(p, q *[2]*int) {
+ a, b := p[0], p[1]
+ runtime.GC()
+ q[0], q[1] = a, b
+ }
+ `,
+ []string{},
+ []string{"MOVUPS"},
},
{
// check that stack store is optimized away
}
`,
[]string{"TEXT\t.*, [$]0-8"},
+ []string{},
},
// math.Abs using integer registers
{
}
`,
[]string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,"},
+ []string{},
},
// math.Copysign using integer registers
{
}
`,
[]string{"\tSHLQ\t[$]1,", "\tSHRQ\t[$]1,", "\tSHRQ\t[$]63,", "\tSHLQ\t[$]63,", "\tORQ\t"},
+ []string{},
},
// int <-> fp moves
{
}
`,
[]string{"\tMOVQ\tX.*, [^X].*"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVL\tX.*, [^X].*"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVQ\t[^X].*, X.*"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVL\t[^X].*, X.*"},
+ []string{},
},
}
}
`,
[]string{"\tMOVL\t\\(.*\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
+ []string{},
},
// multiplication merging tests
return 9*n + 14*n
}`,
[]string{"\tIMULL\t[$]23"}, // 23*n
+ []string{},
},
{
`
return 19*a + a*n
}`,
[]string{"\tADDL\t[$]19", "\tIMULL"}, // (n+19)*a
+ []string{},
},
{
// check that stack store is optimized away
}
`,
[]string{"TEXT\t.*, [$]0-4"},
+ []string{},
},
}
}
`,
[]string{"\tMOVWBR\t\\(.*\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVWBR\t\\(.*\\)\\(.*\\*1\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVDBR\t\\(.*\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVDBR\t\\(.*\\)\\(.*\\*1\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVWZ\t\\(.*\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVWZ\t\\(.*\\)\\(.*\\*1\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVD\t\\(.*\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVD\t\\(.*\\)\\(.*\\*1\\),"},
+ []string{},
},
{
`
}
`,
[]string{"\tRLLG\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tRLLG\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tRLLG\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tRLL\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tRLL\t[$]7,"},
+ []string{},
},
{
`
}
`,
[]string{"\tRLL\t[$]7,"},
+ []string{},
},
// Fused multiply-add/sub instructions.
{
}
`,
[]string{"\tFMADD\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFMSUB\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFMADDS\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFMSUBS\t"},
+ []string{},
},
// Intrinsic tests for math/bits
{
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t", "\tMOVWZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t", "\tOR\t\\$65536,"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t", "\tOR\t\\$256,"},
+ []string{},
},
// Intrinsic tests for math/bits
{
}
`,
[]string{"\tMOVDBR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVWBR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFLOGR\t"},
+ []string{},
},
{
// check that stack store is optimized away
}
`,
[]string{"TEXT\t.*, [$]0-8"},
+ []string{},
},
}
}
`,
[]string{"\tMOVW\tR[0-9]+@>25,"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVW\tR[0-9]+@>25,"},
+ []string{},
},
{
`
}
`,
[]string{"\tMOVW\tR[0-9]+@>25,"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
// make sure assembly output has matching offset and base register.
}
`,
[]string{"b\\+4\\(FP\\)"},
+ []string{},
},
{
// check that stack store is optimized away
}
`,
[]string{"TEXT\t.*, [$]-4-4"},
+ []string{},
},
}
}
`,
[]string{"\tROR\t[$]57,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROR\t[$]57,"},
+ []string{},
},
{
`
}
`,
[]string{"\tROR\t[$]57,"},
+ []string{},
},
{
`
}
`,
[]string{"\tRORW\t[$]25,"},
+ []string{},
},
{
`
}
`,
[]string{"\tRORW\t[$]25,"},
+ []string{},
},
{
`
}
`,
[]string{"\tRORW\t[$]25,"},
+ []string{},
},
{
`
}
`,
[]string{"\tREV\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tREVW\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tAND\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tAND\t"},
+ []string{},
},
{
// make sure offsets are folded into load and store.
}
`,
[]string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"},
+ []string{},
},
{
// check that stack store is optimized away
}
`,
[]string{"TEXT\t.*, [$]-8-8"},
+ []string{},
},
}
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tCLZ\t"},
+ []string{},
},
{
// check that stack store is optimized away
}
`,
[]string{"TEXT\t.*, [$]-4-4"},
+ []string{},
},
}
}
`,
[]string{"\tFMADD\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFMSUB\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFMADDS\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tFMSUBS\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tROTLW\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tROTLW\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tROTLW\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tROTL\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tROTL\t"},
+ []string{},
},
{
`
}
`,
[]string{"\tROTL\t"},
+ []string{},
},
{
// check that stack store is optimized away
}
`,
[]string{"TEXT\t.*, [$]0-8"},
+ []string{},
},
}
case OpAMD64MOVQloadidx8:
return rewriteValueAMD64_OpAMD64MOVQloadidx8_0(v)
case OpAMD64MOVQstore:
- return rewriteValueAMD64_OpAMD64MOVQstore_0(v)
+ return rewriteValueAMD64_OpAMD64MOVQstore_0(v) || rewriteValueAMD64_OpAMD64MOVQstore_10(v)
case OpAMD64MOVQstoreconst:
return rewriteValueAMD64_OpAMD64MOVQstoreconst_0(v)
case OpAMD64MOVQstoreconstidx1:
return false
}
func rewriteValueAMD64_OpAMD64MOVBstore_10(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
// match: (MOVBstore [i] {s} p (SHRQconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
// cond: x.Uses == 1 && clobber(x)
// result: (MOVWstore [i-1] {s} p w mem)
v.AddArg(mem)
return true
}
+ // match: (MOVBstore [i] {s} p x1:(MOVBload [j] {s2} p2 mem) mem2:(MOVBstore [i-1] {s} p x2:(MOVBload [j-1] {s2} p2 mem) mem))
+ // cond: x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && clobber(x1) && clobber(x2) && clobber(mem2)
+ // result: (MOVWstore [i-1] {s} p (MOVWload [j-1] {s2} p2 mem) mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[2]
+ p := v.Args[0]
+ x1 := v.Args[1]
+ if x1.Op != OpAMD64MOVBload {
+ break
+ }
+ j := x1.AuxInt
+ s2 := x1.Aux
+ _ = x1.Args[1]
+ p2 := x1.Args[0]
+ mem := x1.Args[1]
+ mem2 := v.Args[2]
+ if mem2.Op != OpAMD64MOVBstore {
+ break
+ }
+ if mem2.AuxInt != i-1 {
+ break
+ }
+ if mem2.Aux != s {
+ break
+ }
+ _ = mem2.Args[2]
+ if p != mem2.Args[0] {
+ break
+ }
+ x2 := mem2.Args[1]
+ if x2.Op != OpAMD64MOVBload {
+ break
+ }
+ if x2.AuxInt != j-1 {
+ break
+ }
+ if x2.Aux != s2 {
+ break
+ }
+ _ = x2.Args[1]
+ if p2 != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ break
+ }
+ if mem != mem2.Args[2] {
+ break
+ }
+ if !(x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && clobber(x1) && clobber(x2) && clobber(mem2)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Pos, OpAMD64MOVWload, typ.UInt16)
+ v0.AuxInt = j - 1
+ v0.Aux = s2
+ v0.AddArg(p2)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
// cond: canMergeSym(sym1, sym2)
// result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
return false
}
func rewriteValueAMD64_OpAMD64MOVLstore_10(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (MOVLstore [i] {s} p x1:(MOVLload [j] {s2} p2 mem) mem2:(MOVLstore [i-4] {s} p x2:(MOVLload [j-4] {s2} p2 mem) mem))
+ // cond: x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && clobber(x1) && clobber(x2) && clobber(mem2)
+ // result: (MOVQstore [i-4] {s} p (MOVQload [j-4] {s2} p2 mem) mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[2]
+ p := v.Args[0]
+ x1 := v.Args[1]
+ if x1.Op != OpAMD64MOVLload {
+ break
+ }
+ j := x1.AuxInt
+ s2 := x1.Aux
+ _ = x1.Args[1]
+ p2 := x1.Args[0]
+ mem := x1.Args[1]
+ mem2 := v.Args[2]
+ if mem2.Op != OpAMD64MOVLstore {
+ break
+ }
+ if mem2.AuxInt != i-4 {
+ break
+ }
+ if mem2.Aux != s {
+ break
+ }
+ _ = mem2.Args[2]
+ if p != mem2.Args[0] {
+ break
+ }
+ x2 := mem2.Args[1]
+ if x2.Op != OpAMD64MOVLload {
+ break
+ }
+ if x2.AuxInt != j-4 {
+ break
+ }
+ if x2.Aux != s2 {
+ break
+ }
+ _ = x2.Args[1]
+ if p2 != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ break
+ }
+ if mem != mem2.Args[2] {
+ break
+ }
+ if !(x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && clobber(x1) && clobber(x2) && clobber(mem2)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Pos, OpAMD64MOVQload, typ.UInt64)
+ v0.AuxInt = j - 4
+ v0.Aux = s2
+ v0.AddArg(p2)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
// cond: canMergeSym(sym1, sym2)
// result: (MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
return false
}
func rewriteValueAMD64_OpAMD64MOVQstore_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ config := b.Func.Config
+ _ = config
// match: (MOVQstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
// cond: is32Bit(off1+off2)
// result: (MOVQstore [off1+off2] {sym} ptr val mem)
v.AddArg(mem)
return true
}
+ // match: (MOVQstore [i] {s} p x1:(MOVQload [j] {s2} p2 mem) mem2:(MOVQstore [i-8] {s} p x2:(MOVQload [j-8] {s2} p2 mem) mem))
+ // cond: x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && config.useSSE && clobber(x1) && clobber(x2) && clobber(mem2)
+ // result: (MOVOstore [i-8] {s} p (MOVOload [j-8] {s2} p2 mem) mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[2]
+ p := v.Args[0]
+ x1 := v.Args[1]
+ if x1.Op != OpAMD64MOVQload {
+ break
+ }
+ j := x1.AuxInt
+ s2 := x1.Aux
+ _ = x1.Args[1]
+ p2 := x1.Args[0]
+ mem := x1.Args[1]
+ mem2 := v.Args[2]
+ if mem2.Op != OpAMD64MOVQstore {
+ break
+ }
+ if mem2.AuxInt != i-8 {
+ break
+ }
+ if mem2.Aux != s {
+ break
+ }
+ _ = mem2.Args[2]
+ if p != mem2.Args[0] {
+ break
+ }
+ x2 := mem2.Args[1]
+ if x2.Op != OpAMD64MOVQload {
+ break
+ }
+ if x2.AuxInt != j-8 {
+ break
+ }
+ if x2.Aux != s2 {
+ break
+ }
+ _ = x2.Args[1]
+ if p2 != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ break
+ }
+ if mem != mem2.Args[2] {
+ break
+ }
+ if !(x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && config.useSSE && clobber(x1) && clobber(x2) && clobber(mem2)) {
+ break
+ }
+ v.reset(OpAMD64MOVOstore)
+ v.AuxInt = i - 8
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Pos, OpAMD64MOVOload, types.TypeInt128)
+ v0.AuxInt = j - 8
+ v0.Aux = s2
+ v0.AddArg(p2)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVQstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
// cond: canMergeSym(sym1, sym2)
// result: (MOVQstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
v.AddArg(mem)
return true
}
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstore_10(v *Value) bool {
// match: (MOVQstore [off] {sym} ptr (MOVQf2i val) mem)
// cond:
// result: (MOVSDstore [off] {sym} ptr val mem)
return false
}
func rewriteValueAMD64_OpAMD64MOVWstore_10(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (MOVWstore [i] {s} p x1:(MOVWload [j] {s2} p2 mem) mem2:(MOVWstore [i-2] {s} p x2:(MOVWload [j-2] {s2} p2 mem) mem))
+ // cond: x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && clobber(x1) && clobber(x2) && clobber(mem2)
+ // result: (MOVLstore [i-2] {s} p (MOVLload [j-2] {s2} p2 mem) mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ _ = v.Args[2]
+ p := v.Args[0]
+ x1 := v.Args[1]
+ if x1.Op != OpAMD64MOVWload {
+ break
+ }
+ j := x1.AuxInt
+ s2 := x1.Aux
+ _ = x1.Args[1]
+ p2 := x1.Args[0]
+ mem := x1.Args[1]
+ mem2 := v.Args[2]
+ if mem2.Op != OpAMD64MOVWstore {
+ break
+ }
+ if mem2.AuxInt != i-2 {
+ break
+ }
+ if mem2.Aux != s {
+ break
+ }
+ _ = mem2.Args[2]
+ if p != mem2.Args[0] {
+ break
+ }
+ x2 := mem2.Args[1]
+ if x2.Op != OpAMD64MOVWload {
+ break
+ }
+ if x2.AuxInt != j-2 {
+ break
+ }
+ if x2.Aux != s2 {
+ break
+ }
+ _ = x2.Args[1]
+ if p2 != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ break
+ }
+ if mem != mem2.Args[2] {
+ break
+ }
+ if !(x1.Uses == 1 && x2.Uses == 1 && mem2.Uses == 1 && clobber(x1) && clobber(x2) && clobber(mem2)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Pos, OpAMD64MOVLload, typ.UInt32)
+ v0.AuxInt = j - 2
+ v0.Aux = s2
+ v0.AddArg(p2)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
// match: (MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
// cond: canMergeSym(sym1, sym2)
// result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)