go source for verification 2026-05-22
This commit is contained in:
159
test/codegen/README
Normal file
159
test/codegen/README
Normal file
@@ -0,0 +1,159 @@
|
||||
// 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.
|
||||
|
||||
The codegen directory contains code generation tests for the gc
|
||||
compiler.
|
||||
|
||||
|
||||
- Introduction
|
||||
|
||||
The test harness compiles Go code inside files in this directory and
|
||||
matches the generated assembly (the output of `go tool compile -S`)
|
||||
against a set of regexps to be specified in comments that follow a
|
||||
special syntax (described below). The test driver is implemented as
|
||||
an action within the GOROOT/test test suite, called "asmcheck".
|
||||
|
||||
The codegen harness is part of the all.bash test suite, but for
|
||||
performance reasons only the codegen tests for the host machine's
|
||||
GOARCH are enabled by default, and only on GOOS=linux.
|
||||
|
||||
To perform comprehensive tests for all the supported architectures
|
||||
(even on a non-Linux system), one can run the following command:
|
||||
|
||||
$ ../../bin/go test cmd/internal/testdir -run='Test/codegen' -all_codegen -v
|
||||
|
||||
This is recommended after any change that affect the compiler's code.
|
||||
|
||||
The test harness compiles the tests with the same go toolchain that is
|
||||
used to run the test. After writing tests for a newly added codegen
|
||||
transformation, it can be useful to first run the test harness with a
|
||||
toolchain from a released Go version (and verify that the new tests
|
||||
fail), and then re-running the tests using the devel toolchain.
|
||||
|
||||
|
||||
- Regexps comments syntax
|
||||
|
||||
Instructions to match are specified inside plain comments that start
|
||||
with an architecture tag, followed by a colon and a quoted Go-style
|
||||
regexp to be matched. For example, the following test:
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
// amd64:"SQRTSD"
|
||||
// arm64:"FSQRTD"
|
||||
return math.Sqrt(x)
|
||||
}
|
||||
|
||||
verifies that math.Sqrt calls are intrinsified to a SQRTSD instruction
|
||||
on amd64, and to a FSQRTD instruction on arm64.
|
||||
|
||||
It is possible to put multiple architectures checks into the same
|
||||
line, as:
|
||||
|
||||
// amd64:"SQRTSD" arm64:"FSQRTD"
|
||||
|
||||
although this form should be avoided when doing so would make the
|
||||
regexps line excessively long and difficult to read.
|
||||
|
||||
Comments that are on their own line will be matched against the first
|
||||
subsequent non-comment line. Inline comments are also supported; the
|
||||
regexp will be matched against the code found on the same line:
|
||||
|
||||
func Sqrt(x float64) float64 {
|
||||
return math.Sqrt(x) // arm:"SQRTD"
|
||||
}
|
||||
|
||||
It's possible to specify a comma-separated list of regexps to be
|
||||
matched. For example, the following test:
|
||||
|
||||
func TZ8(n uint8) int {
|
||||
// amd64:"BSFQ","ORQ\t\\$256"
|
||||
return bits.TrailingZeros8(n)
|
||||
}
|
||||
|
||||
verifies that the code generated for a bits.TrailingZeros8 call on
|
||||
amd64 contains both a "BSFQ" instruction and an "ORQ $256".
|
||||
|
||||
Note how the ORQ regex includes a tab char (\t). In the Go assembly
|
||||
syntax, operands are separated from opcodes by a tabulation.
|
||||
|
||||
Regexps can be quoted using either " or `. Special characters must be
|
||||
escaped accordingly. Both of these are accepted, and equivalent:
|
||||
|
||||
// amd64:"ADDQ\t\\$3"
|
||||
// amd64:`ADDQ\t\$3`
|
||||
|
||||
and they'll match this assembly line:
|
||||
|
||||
ADDQ $3
|
||||
|
||||
Negative matches can be specified using a - before the quoted regexp.
|
||||
For example:
|
||||
|
||||
func MoveSmall() {
|
||||
x := [...]byte{1, 2, 3, 4, 5, 6, 7}
|
||||
copy(x[1:], x[:]) // arm64:-".*memmove"
|
||||
}
|
||||
|
||||
verifies that NO memmove call is present in the assembly generated for
|
||||
the copy() line.
|
||||
|
||||
The expected number of matches for the regexp can be specified using a
|
||||
positive number:
|
||||
|
||||
func fb(a [4]int) (r [4]int) {
|
||||
// amd64:2`MOVUPS[^,]+, X0$`,2`MOVUPS\sX0,[^\n]+$`
|
||||
return a
|
||||
}
|
||||
|
||||
- Architecture specifiers
|
||||
|
||||
There are three different ways to specify on which architecture a test
|
||||
should be run:
|
||||
|
||||
* Specify only the architecture (eg: "amd64"). This indicates that the
|
||||
check should be run on all the supported architecture variants. For
|
||||
instance, arm checks will be run against all supported GOARM
|
||||
variations (5,6,7).
|
||||
* Specify both the architecture and a variant, separated by a slash
|
||||
(eg: "arm/7"). This means that the check will be run only on that
|
||||
specific variant.
|
||||
* Specify the operating system, the architecture and the variant,
|
||||
separated by slashes (eg: "plan9/386/sse2", "plan9/amd64/"). This is
|
||||
needed in the rare case that you need to do a codegen test affected
|
||||
by a specific operating system; by default, tests are compiled only
|
||||
targeting linux.
|
||||
|
||||
|
||||
- Remarks, and Caveats
|
||||
|
||||
-- Write small test functions
|
||||
|
||||
As a general guideline, test functions should be small, to avoid
|
||||
possible interactions between unrelated lines of code that may be
|
||||
introduced, for example, by the compiler's optimization passes.
|
||||
|
||||
Any given line of Go code could get assigned more instructions than it
|
||||
may appear from reading the source. In particular, matching all MOV
|
||||
instructions should be avoided; the compiler may add them for
|
||||
unrelated reasons and this may render the test ineffective.
|
||||
|
||||
-- Line matching logic
|
||||
|
||||
Regexps are always matched from the start of the instructions line.
|
||||
This means, for example, that the "MULQ" regexp is equivalent to
|
||||
"^MULQ" (^ representing the start of the line), and it will NOT match
|
||||
the following assembly line:
|
||||
|
||||
IMULQ $99, AX
|
||||
|
||||
To force a match at any point of the line, ".*MULQ" should be used.
|
||||
|
||||
For the same reason, a negative regexp like -"memmove" is not enough
|
||||
to make sure that no memmove call is included in the assembly. A
|
||||
memmove call looks like this:
|
||||
|
||||
CALL runtime.memmove(SB)
|
||||
|
||||
To make sure that the "memmove" symbol does not appear anywhere in the
|
||||
assembly, the negative regexp to be used is -".*memmove".
|
||||
14
test/codegen/addrcalc.go
Normal file
14
test/codegen/addrcalc.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2019 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
|
||||
|
||||
// Make sure we use ADDQ instead of LEAQ when we can.
|
||||
|
||||
func f(p *[4][2]int, x int) *int {
|
||||
// amd64:"ADDQ" -"LEAQ"
|
||||
return &p[x][0]
|
||||
}
|
||||
37
test/codegen/alloc.go
Normal file
37
test/codegen/alloc.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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.
|
||||
|
||||
// These tests check that allocating a 0-size object does not
|
||||
// introduce a call to runtime.newobject.
|
||||
|
||||
package codegen
|
||||
|
||||
func zeroAllocNew1() *struct{} {
|
||||
// 386:-`CALL runtime\.newobject`, `LEAL runtime.zerobase`
|
||||
// amd64:-`CALL runtime\.newobject`, `LEAQ runtime.zerobase`
|
||||
// arm:-`CALL runtime\.newobject`, `MOVW [$]runtime.zerobase`
|
||||
// arm64:-`CALL runtime\.newobject`, `MOVD [$]runtime.zerobase`
|
||||
// riscv64:-`CALL runtime\.newobject`, `MOV [$]runtime.zerobase`
|
||||
return new(struct{})
|
||||
}
|
||||
|
||||
func zeroAllocNew2() *[0]int {
|
||||
// 386:-`CALL runtime\.newobject`, `LEAL runtime.zerobase`
|
||||
// amd64:-`CALL runtime\.newobject`, `LEAQ runtime.zerobase`
|
||||
// arm:-`CALL runtime\.newobject`, `MOVW [$]runtime.zerobase`
|
||||
// arm64:-`CALL runtime\.newobject`, `MOVD [$]runtime.zerobase`
|
||||
// riscv64:-`CALL runtime\.newobject`, `MOV [$]runtime.zerobase`
|
||||
return new([0]int)
|
||||
}
|
||||
|
||||
func zeroAllocSliceLit() []int {
|
||||
// 386:-`CALL runtime\.newobject`, `LEAL runtime.zerobase`
|
||||
// amd64:-`CALL runtime\.newobject`, `LEAQ runtime.zerobase`
|
||||
// arm:-`CALL runtime\.newobject`, `MOVW [$]runtime.zerobase`
|
||||
// arm64:-`CALL runtime\.newobject`, `MOVD [$]runtime.zerobase`
|
||||
// riscv64:-`CALL runtime\.newobject`, `MOV [$]runtime.zerobase`
|
||||
return []int{}
|
||||
}
|
||||
245
test/codegen/append.go
Normal file
245
test/codegen/append.go
Normal file
@@ -0,0 +1,245 @@
|
||||
// asmcheck
|
||||
|
||||
//go:build !goexperiment.runtimefreegc
|
||||
|
||||
// Copyright 2025 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
|
||||
|
||||
func Append1(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append2(n int) (r []int) {
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return
|
||||
}
|
||||
|
||||
func Append3(n int) (r []int) {
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append4(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBuf\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
println(cap(r))
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append5(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBuf\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
useSlice(r)
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append5b(n int) []int {
|
||||
var r []int
|
||||
useSlice(r)
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBuf\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append6(n int) []*int {
|
||||
var r []*int
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, new(i))
|
||||
}
|
||||
// amd64:`.*moveSliceNoCap\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append7(n int) []*int {
|
||||
var r []*int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBuf\b`
|
||||
r = append(r, new(i))
|
||||
}
|
||||
println(cap(r))
|
||||
// amd64:`.*moveSlice\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append8(n int, p *[]int) {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
*p = r
|
||||
}
|
||||
|
||||
func Append8b(n int, p *[]int) {
|
||||
var r []int
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
*p = r
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
}
|
||||
|
||||
func Append9(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
println(len(r))
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append10(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
println(r[3])
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append11(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBuf\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
r = r[3:5]
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append12(n int) []int {
|
||||
var r []int
|
||||
r = nil
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append13(n int) []int {
|
||||
var r []int
|
||||
r, r = nil, nil
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append14(n int) []int {
|
||||
var r []int
|
||||
r = []int{3, 4, 5}
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBuf\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append15(n int) []int {
|
||||
r := []int{3, 4, 5}
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBuf\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append16(r []int, n int) []int {
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append17(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
for i, x := range r {
|
||||
println(i, x)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append18(n int, p *[]int) {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:-`.*moveSliceNoCapNoScan`
|
||||
*p = r
|
||||
// amd64:`.*growslice`
|
||||
r = append(r, i)
|
||||
}
|
||||
}
|
||||
|
||||
func Append19(n int, p [][]int) {
|
||||
for j := range p {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growslice`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan`
|
||||
p[j] = r
|
||||
}
|
||||
}
|
||||
|
||||
func Append20(n int, p [][]int) {
|
||||
for j := range p {
|
||||
var r []int
|
||||
// amd64:`.*growslice`
|
||||
r = append(r, 0)
|
||||
// amd64:-`.*moveSliceNoCapNoScan`
|
||||
p[j] = r
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func useSlice(s []int) {
|
||||
}
|
||||
217
test/codegen/append_freegc.go
Normal file
217
test/codegen/append_freegc.go
Normal file
@@ -0,0 +1,217 @@
|
||||
// asmcheck
|
||||
|
||||
//go:build goexperiment.runtimefreegc
|
||||
|
||||
// Copyright 2025 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
|
||||
|
||||
func Append1(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append2(n int) (r []int) {
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return
|
||||
}
|
||||
|
||||
func Append3(n int) (r []int) {
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append4(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBufNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
println(cap(r))
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append5(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBufNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
useSlice(r)
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append5b(n int) []int {
|
||||
var r []int
|
||||
useSlice(r)
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBuf\b` -`.*growsliceBufNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append6(n int) []*int {
|
||||
var r []*int
|
||||
for i := range n {
|
||||
// TODO(thepudds): for now, the compiler only uses the NoAlias version
|
||||
// for element types without pointers.
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, new(i))
|
||||
}
|
||||
// amd64:`.*moveSliceNoCap\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append7(n int) []*int {
|
||||
var r []*int
|
||||
for i := range n {
|
||||
// TODO(thepudds): for now, the compiler only uses the NoAlias version
|
||||
// for element types without pointers.
|
||||
// amd64:`.*growsliceBuf\b`
|
||||
r = append(r, new(i))
|
||||
}
|
||||
println(cap(r))
|
||||
// amd64:`.*moveSlice\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append8(n int, p *[]int) {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
*p = r
|
||||
}
|
||||
|
||||
func Append8b(n int, p *[]int) {
|
||||
var r []int
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
*p = r
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b` -`.*growsliceNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
}
|
||||
|
||||
func Append9(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
println(len(r))
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append10(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
println(r[3])
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append11(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBufNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
r = r[3:5]
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append12(n int) []int {
|
||||
var r []int
|
||||
r = nil
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append13(n int) []int {
|
||||
var r []int
|
||||
r, r = nil, nil
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append14(n int) []int {
|
||||
var r []int
|
||||
r = []int{3, 4, 5}
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBufNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append15(n int) []int {
|
||||
r := []int{3, 4, 5}
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceBufNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append16(r []int, n int) []int {
|
||||
for i := range n {
|
||||
// amd64:`.*growslice\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
func Append17(n int) []int {
|
||||
var r []int
|
||||
for i := range n {
|
||||
// amd64:`.*growsliceNoAlias\b`
|
||||
r = append(r, i)
|
||||
}
|
||||
for i, x := range r {
|
||||
println(i, x)
|
||||
}
|
||||
// amd64:`.*moveSliceNoCapNoScan\b`
|
||||
return r
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func useSlice(s []int) {
|
||||
}
|
||||
791
test/codegen/arithmetic.go
Normal file
791
test/codegen/arithmetic.go
Normal file
@@ -0,0 +1,791 @@
|
||||
// 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
|
||||
|
||||
// This file contains codegen tests related to arithmetic
|
||||
// simplifications and optimizations on integer types.
|
||||
// For codegen tests on float types, see floats.go.
|
||||
|
||||
// Addition
|
||||
|
||||
func AddLargeConst(a uint64, out []uint64) {
|
||||
// ppc64x/power10:"ADD [$]4294967296,"
|
||||
// ppc64x/power9:"MOVD [$]1", "SLD [$]32" "ADD R[0-9]*"
|
||||
// ppc64x/power8:"MOVD [$]1", "SLD [$]32" "ADD R[0-9]*"
|
||||
out[0] = a + 0x100000000
|
||||
// ppc64x/power10:"ADD [$]-8589934592,"
|
||||
// ppc64x/power9:"MOVD [$]-1", "SLD [$]33" "ADD R[0-9]*"
|
||||
// ppc64x/power8:"MOVD [$]-1", "SLD [$]33" "ADD R[0-9]*"
|
||||
out[1] = a + 0xFFFFFFFE00000000
|
||||
// ppc64x/power10:"ADD [$]1234567,"
|
||||
// ppc64x/power9:"ADDIS [$]19,", "ADD [$]-10617,"
|
||||
// ppc64x/power8:"ADDIS [$]19,", "ADD [$]-10617,"
|
||||
out[2] = a + 1234567
|
||||
// ppc64x/power10:"ADD [$]-1234567,"
|
||||
// ppc64x/power9:"ADDIS [$]-19,", "ADD [$]10617,"
|
||||
// ppc64x/power8:"ADDIS [$]-19,", "ADD [$]10617,"
|
||||
out[3] = a - 1234567
|
||||
// ppc64x/power10:"ADD [$]2147450879,"
|
||||
// ppc64x/power9:"ADDIS [$]32767,", "ADD [$]32767,"
|
||||
// ppc64x/power8:"ADDIS [$]32767,", "ADD [$]32767,"
|
||||
out[4] = a + 0x7FFF7FFF
|
||||
// ppc64x/power10:"ADD [$]-2147483647,"
|
||||
// ppc64x/power9:"ADDIS [$]-32768,", "ADD [$]1,"
|
||||
// ppc64x/power8:"ADDIS [$]-32768,", "ADD [$]1,"
|
||||
out[5] = a - 2147483647
|
||||
// ppc64x:"ADDIS [$]-32768,", ^"ADD "
|
||||
out[6] = a - 2147483648
|
||||
// ppc64x:"ADD [$]2147450880,", ^"ADDIS "
|
||||
out[7] = a + 0x7FFF8000
|
||||
// ppc64x:"ADD [$]-32768,", ^"ADDIS "
|
||||
out[8] = a - 32768
|
||||
// ppc64x/power10:"ADD [$]-32769,"
|
||||
// ppc64x/power9:"ADDIS [$]-1,", "ADD [$]32767,"
|
||||
// ppc64x/power8:"ADDIS [$]-1,", "ADD [$]32767,"
|
||||
out[9] = a - 32769
|
||||
}
|
||||
|
||||
func AddLargeConst2(a int, out []int) {
|
||||
// loong64: -"ADDVU" "ADDV16"
|
||||
out[0] = a + 0x10000
|
||||
}
|
||||
|
||||
// Subtraction
|
||||
|
||||
var ef int
|
||||
|
||||
func SubMem(arr []int, b, c, d int) int {
|
||||
// 386:`SUBL\s[A-Z]+,\s8\([A-Z]+\)`
|
||||
// amd64:`SUBQ\s[A-Z]+,\s16\([A-Z]+\)`
|
||||
arr[2] -= b
|
||||
// 386:`SUBL\s[A-Z]+,\s12\([A-Z]+\)`
|
||||
// amd64:`SUBQ\s[A-Z]+,\s24\([A-Z]+\)`
|
||||
arr[3] -= b
|
||||
// 386:`DECL\s16\([A-Z]+\)`
|
||||
arr[4]--
|
||||
// 386:`ADDL\s[$]-20,\s20\([A-Z]+\)`
|
||||
arr[5] -= 20
|
||||
// 386:`SUBL\s\([A-Z]+\)\([A-Z]+\*4\),\s[A-Z]+`
|
||||
ef -= arr[b]
|
||||
// 386:`SUBL\s[A-Z]+,\s\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
arr[c] -= b
|
||||
// 386:`ADDL\s[$]-15,\s\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
arr[d] -= 15
|
||||
// 386:`DECL\s\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
arr[b]--
|
||||
// amd64:`DECQ\s64\([A-Z]+\)`
|
||||
arr[8]--
|
||||
// 386:"SUBL 4"
|
||||
// amd64:"SUBQ 8"
|
||||
return arr[0] - arr[1]
|
||||
}
|
||||
|
||||
func SubFromConst(a int) int {
|
||||
// ppc64x: `SUBC R[0-9]+,\s[$]40,\sR`
|
||||
// riscv64: "ADDI [$]-40" "NEG"
|
||||
b := 40 - a
|
||||
return b
|
||||
}
|
||||
|
||||
func SubFromConstNeg(a int) int {
|
||||
// arm64: "ADD [$]40"
|
||||
// loong64: "ADDV[U] [$]40"
|
||||
// mips: "ADD[U] [$]40"
|
||||
// mips64: "ADDV[U] [$]40"
|
||||
// ppc64x: `ADD [$]40,\sR[0-9]+,\sR`
|
||||
// riscv64: "ADDI [$]40" -"NEG"
|
||||
c := 40 - (-a)
|
||||
return c
|
||||
}
|
||||
|
||||
func SubSubFromConst(a int) int {
|
||||
// arm64: "ADD [$]20"
|
||||
// loong64: "ADDV[U] [$]20"
|
||||
// mips: "ADD[U] [$]20"
|
||||
// mips64: "ADDV[U] [$]20"
|
||||
// ppc64x: `ADD [$]20,\sR[0-9]+,\sR`
|
||||
// riscv64: "ADDI [$]20" -"NEG"
|
||||
c := 40 - (20 - a)
|
||||
return c
|
||||
}
|
||||
|
||||
func AddSubFromConst(a int) int {
|
||||
// ppc64x: `SUBC R[0-9]+,\s[$]60,\sR`
|
||||
// riscv64: "ADDI [$]-60" "NEG"
|
||||
c := 40 + (20 - a)
|
||||
return c
|
||||
}
|
||||
|
||||
func NegSubFromConst(a int) int {
|
||||
// arm64: "SUB [$]20"
|
||||
// loong64: "ADDV[U] [$]-20"
|
||||
// mips: "ADD[U] [$]-20"
|
||||
// mips64: "ADDV[U] [$]-20"
|
||||
// ppc64x: `ADD [$]-20,\sR[0-9]+,\sR`
|
||||
// riscv64: "ADDI [$]-20"
|
||||
c := -(20 - a)
|
||||
return c
|
||||
}
|
||||
|
||||
func NegAddFromConstNeg(a int) int {
|
||||
// arm64: "SUB [$]40" "NEG"
|
||||
// loong64: "ADDV[U] [$]-40" "SUBV"
|
||||
// mips: "ADD[U] [$]-40" "SUB"
|
||||
// mips64: "ADDV[U] [$]-40" "SUBV"
|
||||
// ppc64x: `SUBC R[0-9]+,\s[$]40,\sR`
|
||||
// riscv64: "ADDI [$]-40" "NEG"
|
||||
c := -(-40 + a)
|
||||
return c
|
||||
}
|
||||
|
||||
func SubSubNegSimplify(a, b int) int {
|
||||
// amd64:"NEGQ"
|
||||
// arm64:"NEG"
|
||||
// loong64:"SUBV"
|
||||
// mips:"SUB"
|
||||
// mips64:"SUBV"
|
||||
// ppc64x:"NEG"
|
||||
// riscv64:"NEG" -"SUB"
|
||||
r := (a - b) - a
|
||||
return r
|
||||
}
|
||||
|
||||
func SubAddSimplify(a, b int) int {
|
||||
// amd64:-"SUBQ" -"ADDQ"
|
||||
// arm64:-"SUB" -"ADD"
|
||||
// loong64:-"SUBV" -"ADDV"
|
||||
// mips:-"SUB" -"ADD"
|
||||
// mips64:-"SUBV" -"ADDV"
|
||||
// ppc64x:-"SUB" -"ADD"
|
||||
// riscv64:-"SUB" -"ADD"
|
||||
r := a + (b - a)
|
||||
return r
|
||||
}
|
||||
|
||||
func SubAddSimplify2(a, b, c int) (int, int, int, int, int, int) {
|
||||
// amd64:-"ADDQ"
|
||||
// arm64:-"ADD"
|
||||
// mips:"SUB" -"ADD"
|
||||
// mips64:"SUBV" -"ADDV"
|
||||
// loong64:"SUBV" -"ADDV"
|
||||
// riscv64:-"ADD"
|
||||
r := (a + b) - (a + c)
|
||||
// amd64:-"ADDQ"
|
||||
// riscv64:-"ADD"
|
||||
r1 := (a + b) - (c + a)
|
||||
// amd64:-"ADDQ"
|
||||
// riscv64:-"ADD"
|
||||
r2 := (b + a) - (a + c)
|
||||
// amd64:-"ADDQ"
|
||||
// riscv64:-"ADD"
|
||||
r3 := (b + a) - (c + a)
|
||||
// amd64:-"SUBQ"
|
||||
// arm64:-"SUB"
|
||||
// mips:"ADD" -"SUB"
|
||||
// mips64:"ADDV" -"SUBV"
|
||||
// loong64:"ADDV" -"SUBV"
|
||||
// riscv64:-"SUB"
|
||||
r4 := (a - c) + (c + b)
|
||||
// amd64:-"SUBQ"
|
||||
// riscv64:-"SUB"
|
||||
r5 := (a - c) + (b + c)
|
||||
return r, r1, r2, r3, r4, r5
|
||||
}
|
||||
|
||||
func SubAddNegSimplify(a, b int) int {
|
||||
// amd64:"NEGQ" -"ADDQ" -"SUBQ"
|
||||
// arm64:"NEG" -"ADD" -"SUB"
|
||||
// loong64:"SUBV" -"ADDV"
|
||||
// mips:"SUB" -"ADD"
|
||||
// mips64:"SUBV" -"ADDV"
|
||||
// ppc64x:"NEG" -"ADD" -"SUB"
|
||||
// riscv64:"NEG" -"ADD" -"SUB"
|
||||
r := a - (b + a)
|
||||
return r
|
||||
}
|
||||
|
||||
func AddAddSubSimplify(a, b, c int) int {
|
||||
// amd64:-"SUBQ"
|
||||
// arm64:"ADD" -"SUB"
|
||||
// loong64:"ADDV" -"SUBV"
|
||||
// mips:"ADD" -"SUB"
|
||||
// mips64:"ADDV" -"SUBV"
|
||||
// ppc64x:-"SUB"
|
||||
// riscv64:"ADD" "ADD" -"SUB"
|
||||
r := a + (b + (c - a))
|
||||
return r
|
||||
}
|
||||
|
||||
func NegToInt32(a int) int {
|
||||
// riscv64: "NEGW" -"MOVW"
|
||||
r := int(int32(-a))
|
||||
return r
|
||||
}
|
||||
|
||||
// -------------------- //
|
||||
// Multiplication //
|
||||
// -------------------- //
|
||||
|
||||
func Pow2Muls(n1, n2 int) (int, int) {
|
||||
// amd64:"SHLQ [$]5" -"IMULQ"
|
||||
// 386:"SHLL [$]5" -"IMULL"
|
||||
// arm:"SLL [$]5" -"MUL"
|
||||
// arm64:"LSL [$]5" -"MUL"
|
||||
// loong64:"SLLV [$]5" -"MULV"
|
||||
// ppc64x:"SLD [$]5" -"MUL"
|
||||
a := n1 * 32
|
||||
|
||||
// amd64:"SHLQ [$]6" -"IMULQ"
|
||||
// 386:"SHLL [$]6" -"IMULL"
|
||||
// arm:"SLL [$]6" -"MUL"
|
||||
// arm64:`NEG\sR[0-9]+<<6,\sR[0-9]+`,-`LSL`,-`MUL`
|
||||
// loong64:"SLLV [$]6" -"MULV"
|
||||
// ppc64x:"SLD [$]6" "NEG\\sR[0-9]+,\\sR[0-9]+" -"MUL"
|
||||
b := -64 * n2
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
func Mul_2(n1 int32, n2 int64) (int32, int64) {
|
||||
// amd64:"ADDL", -"SHLL"
|
||||
a := n1 * 2
|
||||
// amd64:"ADDQ", -"SHLQ"
|
||||
b := n2 * 2
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
func Mul_96(n int) int {
|
||||
// amd64:`SHLQ [$]5`,`LEAQ \(.*\)\(.*\*2\),`,-`IMULQ`
|
||||
// 386:`SHLL [$]5`,`LEAL \(.*\)\(.*\*2\),`,-`IMULL`
|
||||
// arm64:`LSL [$]5`,`ADD\sR[0-9]+<<1,\sR[0-9]+`,-`MUL`
|
||||
// arm:`SLL [$]5`,`ADD\sR[0-9]+<<1,\sR[0-9]+`,-`MUL`
|
||||
// loong64:"SLLV [$]5" "ALSLV [$]1,"
|
||||
// s390x:`SLD [$]5`,`SLD [$]6`,-`MULLD`
|
||||
return n * 96
|
||||
}
|
||||
|
||||
func Mul_n120(n int) int {
|
||||
// loong64:"SLLV [$]3" "SLLV [$]7" "SUBVU" -"MULV"
|
||||
// s390x:`SLD [$]3`,`SLD [$]7`,-`MULLD`
|
||||
return n * -120
|
||||
}
|
||||
|
||||
func MulMemSrc(a []uint32, b []float32) {
|
||||
// 386:`IMULL\s4\([A-Z]+\),\s[A-Z]+`
|
||||
a[0] *= a[1]
|
||||
// 386/sse2:`MULSS\s4\([A-Z]+\),\sX[0-9]+`
|
||||
// amd64:`MULSS\s4\([A-Z]+\),\sX[0-9]+`
|
||||
b[0] *= b[1]
|
||||
}
|
||||
|
||||
// Multiplications merging tests
|
||||
|
||||
func MergeMuls1(n int) int {
|
||||
// amd64:"IMUL3Q [$]46"
|
||||
// 386:"IMUL3L [$]46"
|
||||
// ppc64x:"MULLD [$]46"
|
||||
return 15*n + 31*n // 46n
|
||||
}
|
||||
|
||||
func MergeMuls2(n int) int {
|
||||
// amd64:"IMUL3Q [$]23" "(ADDQ [$]29)|(LEAQ 29)"
|
||||
// 386:"IMUL3L [$]23" "ADDL [$]29"
|
||||
// ppc64x/power9:"MADDLD" -"MULLD [$]23" -"ADD [$]29"
|
||||
// ppc64x/power8:"MULLD [$]23" "ADD [$]29"
|
||||
return 5*n + 7*(n+1) + 11*(n+2) // 23n + 29
|
||||
}
|
||||
|
||||
func MergeMuls3(a, n int) int {
|
||||
// amd64:"ADDQ [$]19" -"IMULQ [$]19"
|
||||
// 386:"ADDL [$]19" -"IMULL [$]19"
|
||||
// ppc64x:"ADD [$]19" -"MULLD [$]19"
|
||||
return a*n + 19*n // (a+19)n
|
||||
}
|
||||
|
||||
func MergeMuls4(n int) int {
|
||||
// amd64:"IMUL3Q [$]14"
|
||||
// 386:"IMUL3L [$]14"
|
||||
// ppc64x:"MULLD [$]14"
|
||||
return 23*n - 9*n // 14n
|
||||
}
|
||||
|
||||
func MergeMuls5(a, n int) int {
|
||||
// amd64:"ADDQ [$]-19" -"IMULQ [$]19"
|
||||
// 386:"ADDL [$]-19" -"IMULL [$]19"
|
||||
// ppc64x:"ADD [$]-19" -"MULLD [$]19"
|
||||
return a*n - 19*n // (a-19)n
|
||||
}
|
||||
|
||||
// Multiplications folded negation
|
||||
|
||||
func FoldNegMul(a int) int {
|
||||
// amd64:"IMUL3Q [$]-11" -"NEGQ"
|
||||
// arm64:"MOVD [$]-11" "MUL" -"NEG"
|
||||
// loong64:"ALSLV [$]2" "SUBVU" "ALSLV [$]4"
|
||||
// riscv64:"MOV [$]-11" "MUL" -"NEG"
|
||||
return -a * 11
|
||||
}
|
||||
|
||||
func Fold2NegMul(a, b int) int {
|
||||
// amd64:"IMULQ" -"NEGQ"
|
||||
// arm64:"MUL" -"NEG"
|
||||
// loong64:"MULV" -"SUBVU R[0-9], R0,"
|
||||
// riscv64:"MUL" -"NEG"
|
||||
return -a * -b
|
||||
}
|
||||
|
||||
func Mul32(a, b int32) int64 {
|
||||
// arm64:"SMULL" -"MOVW"
|
||||
// loong64:"MULWVW" -"MOVW"
|
||||
return int64(a) * int64(b)
|
||||
}
|
||||
|
||||
func Mul32U(a, b uint32) uint64 {
|
||||
// arm64:"UMULL" -"MOVWU"
|
||||
// loong64:"MULWVWU" -"MOVWU"
|
||||
return uint64(a) * uint64(b)
|
||||
}
|
||||
|
||||
func SimplifyNegMulConst(a int) int {
|
||||
// amd64:-"NEGQ"
|
||||
// arm64:"MOVD [$]11" "MUL" -"NEG"
|
||||
// riscv64:"MOV [$]11" "MUL" -"NEG"
|
||||
return -(a * -11)
|
||||
}
|
||||
|
||||
func SimplifyNegMul(a, b int) int {
|
||||
// amd64:-"NEGQ"
|
||||
// arm64:"MUL" -"NEG"
|
||||
// riscv64:"MUL" -"NEG"
|
||||
return -(-a * b)
|
||||
}
|
||||
|
||||
// -------------- //
|
||||
// Division //
|
||||
// -------------- //
|
||||
|
||||
func DivMemSrc(a []float64) {
|
||||
// 386/sse2:`DIVSD\s8\([A-Z]+\),\sX[0-9]+`
|
||||
// amd64:`DIVSD\s8\([A-Z]+\),\sX[0-9]+`
|
||||
a[0] /= a[1]
|
||||
}
|
||||
|
||||
func Pow2Divs(n1 uint, n2 int) (uint, int) {
|
||||
// 386:"SHRL [$]5" -"DIVL"
|
||||
// amd64:"SHRQ [$]5" -"DIVQ"
|
||||
// arm:"SRL [$]5" -".*udiv"
|
||||
// arm64:"LSR [$]5" -"UDIV"
|
||||
// ppc64x:"SRD"
|
||||
a := n1 / 32 // unsigned
|
||||
|
||||
// amd64:"SARQ [$]6" -"IDIVQ"
|
||||
// 386:"SARL [$]6" -"IDIVL"
|
||||
// arm:"SRA [$]6" -".*udiv"
|
||||
// arm64:"ASR [$]6" -"SDIV"
|
||||
// ppc64x:"SRAD"
|
||||
b := n2 / 64 // signed
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
// Check that constant divisions get turned into MULs
|
||||
func ConstDivs(n1 uint, n2 int) (uint, int) {
|
||||
// amd64: "MOVQ [$]-1085102592571150095" "MULQ" -"DIVQ"
|
||||
// 386: "MOVL [$]-252645135" "MULL" -"DIVL"
|
||||
// arm64: `MOVD`,`UMULH`,-`DIV`
|
||||
// arm: `MOVW`,`MUL`,-`.*udiv`
|
||||
a := n1 / 17 // unsigned
|
||||
|
||||
// amd64: "MOVQ [$]-1085102592571150095" "IMULQ" -"IDIVQ"
|
||||
// 386: "IMULL" "SARL [$]4," "SARL [$]31," "SUBL" -".*DIV"
|
||||
// arm64: `SMULH` -`DIV`
|
||||
// arm: `MOVW` `MUL` -`.*udiv`
|
||||
b := n2 / 17 // signed
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
func FloatDivs(a []float32) float32 {
|
||||
// amd64:`DIVSS\s8\([A-Z]+\),\sX[0-9]+`
|
||||
// 386/sse2:`DIVSS\s8\([A-Z]+\),\sX[0-9]+`
|
||||
return a[1] / a[2]
|
||||
}
|
||||
|
||||
func Pow2Mods(n1 uint, n2 int) (uint, int) {
|
||||
// 386:"ANDL [$]31" -"DIVL"
|
||||
// amd64:"ANDL [$]31" -"DIVQ"
|
||||
// arm:"AND [$]31" -".*udiv"
|
||||
// arm64:"AND [$]31" -"UDIV"
|
||||
// ppc64x:"RLDICL"
|
||||
a := n1 % 32 // unsigned
|
||||
|
||||
// 386:"SHRL" -"IDIVL"
|
||||
// amd64:"SHRQ" -"IDIVQ"
|
||||
// arm:"SRA" -".*udiv"
|
||||
// arm64:"ASR" -"REM"
|
||||
// ppc64x:"SRAD"
|
||||
b := n2 % 64 // signed
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
// Check that signed divisibility checks get converted to AND on low bits
|
||||
func Pow2DivisibleSigned(n1, n2 int) (bool, bool) {
|
||||
// 386:"TESTL [$]63" -"DIVL" -"SHRL"
|
||||
// amd64:"TESTQ [$]63" -"DIVQ" -"SHRQ"
|
||||
// arm:"AND [$]63" -".*udiv" -"SRA"
|
||||
// arm64:"TST [$]63" -"UDIV" -"ASR" -"AND"
|
||||
// ppc64x:"ANDCC" -"RLDICL" -"SRAD" -"CMP"
|
||||
a := n1%64 == 0 // signed divisible
|
||||
|
||||
// 386:"TESTL [$]63" -"DIVL" -"SHRL"
|
||||
// amd64:"TESTQ [$]63" -"DIVQ" -"SHRQ"
|
||||
// arm:"AND [$]63" -".*udiv" -"SRA"
|
||||
// arm64:"TST [$]63" -"UDIV" -"ASR" -"AND"
|
||||
// ppc64x:"ANDCC" -"RLDICL" -"SRAD" -"CMP"
|
||||
b := n2%64 != 0 // signed indivisible
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
// Check that constant modulo divs get turned into MULs
|
||||
func ConstMods(n1 uint, n2 int) (uint, int) {
|
||||
// amd64: "MOVQ [$]-1085102592571150095" "MULQ" -"DIVQ"
|
||||
// 386: "MOVL [$]-252645135" "MULL" -".*DIVL"
|
||||
// arm64: `MOVD` `UMULH` -`DIV`
|
||||
// arm: `MOVW` `MUL` -`.*udiv`
|
||||
a := n1 % 17 // unsigned
|
||||
|
||||
// amd64: "MOVQ [$]-1085102592571150095" "IMULQ" -"IDIVQ"
|
||||
// 386: "IMULL" "SARL [$]4," "SARL [$]31," "SUBL" "SHLL [$]4," "SUBL" -".*DIV"
|
||||
// arm64: `SMULH` -`DIV`
|
||||
// arm: `MOVW` `MUL` -`.*udiv`
|
||||
b := n2 % 17 // signed
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
// Check that divisibility checks x%c==0 are converted to MULs and rotates
|
||||
func DivisibleU(n uint) (bool, bool) {
|
||||
// amd64:"MOVQ [$]-6148914691236517205" "IMULQ" "ROLQ [$]63" -"DIVQ"
|
||||
// 386:"IMUL3L [$]-1431655765" "ROLL [$]31" -"DIVQ"
|
||||
// arm64:"MOVD [$]-6148914691236517205" "MOVD [$]3074457345618258602" "MUL" "ROR" -"DIV"
|
||||
// arm:"MUL" "CMP [$]715827882" -".*udiv"
|
||||
// ppc64x:"MULLD" "ROTL [$]63"
|
||||
even := n%6 == 0
|
||||
|
||||
// amd64:"MOVQ [$]-8737931403336103397" "IMULQ" -"ROLQ" -"DIVQ"
|
||||
// 386:"IMUL3L [$]678152731" -"ROLL" -"DIVQ"
|
||||
// arm64:"MOVD [$]-8737931403336103397" "MUL" -"ROR" -"DIV"
|
||||
// arm:"MUL" "CMP [$]226050910" -".*udiv"
|
||||
// ppc64x:"MULLD" -"ROTL"
|
||||
odd := n%19 == 0
|
||||
|
||||
return even, odd
|
||||
}
|
||||
|
||||
func Divisible(n int) (bool, bool) {
|
||||
// amd64:"IMULQ" "ADD" "ROLQ [$]63" -"DIVQ"
|
||||
// 386:"IMUL3L [$]-1431655765" "ADDL [$]715827882" "ROLL [$]31" -"DIVQ"
|
||||
// arm64:"MOVD [$]-6148914691236517205" "MOVD [$]3074457345618258602" "MUL" "ADD R" "ROR" -"DIV"
|
||||
// arm:"MUL" "ADD [$]715827882" -".*udiv"
|
||||
// ppc64x/power8:"MULLD" "ADD" "ROTL [$]63"
|
||||
// ppc64x/power9:"MADDLD" "ROTL [$]63"
|
||||
even := n%6 == 0
|
||||
|
||||
// amd64:"IMULQ" "ADD" -"ROLQ" -"DIVQ"
|
||||
// 386:"IMUL3L [$]678152731" "ADDL [$]113025455" -"ROLL" -"DIVQ"
|
||||
// arm64:"MUL" "MOVD [$]485440633518672410" "ADD" -"ROR" -"DIV"
|
||||
// arm:"MUL" "ADD [$]113025455" -".*udiv"
|
||||
// ppc64x/power8:"MULLD" "ADD" -"ROTL"
|
||||
// ppc64x/power9:"MADDLD" -"ROTL"
|
||||
odd := n%19 == 0
|
||||
|
||||
return even, odd
|
||||
}
|
||||
|
||||
// Check that fix-up code is not generated for divisions where it has been proven that
|
||||
// that the divisor is not -1 or that the dividend is > MinIntNN.
|
||||
func NoFix64A(divr int64) (int64, int64) {
|
||||
var d int64 = 42
|
||||
var e int64 = 84
|
||||
if divr > 5 {
|
||||
d /= divr // amd64:-"JMP"
|
||||
e %= divr // amd64:-"JMP"
|
||||
// The following statement is to avoid conflict between the above check
|
||||
// and the normal JMP generated at the end of the block.
|
||||
d += e
|
||||
}
|
||||
return d, e
|
||||
}
|
||||
|
||||
func NoFix64B(divd int64) (int64, int64) {
|
||||
var d int64
|
||||
var e int64
|
||||
var divr int64 = -1
|
||||
if divd > -9223372036854775808 {
|
||||
d = divd / divr // amd64:-"JMP"
|
||||
e = divd % divr // amd64:-"JMP"
|
||||
d += e
|
||||
}
|
||||
return d, e
|
||||
}
|
||||
|
||||
func NoFix32A(divr int32) (int32, int32) {
|
||||
var d int32 = 42
|
||||
var e int32 = 84
|
||||
if divr > 5 {
|
||||
// amd64:-"JMP"
|
||||
// 386:-"JMP"
|
||||
d /= divr
|
||||
// amd64:-"JMP"
|
||||
// 386:-"JMP"
|
||||
e %= divr
|
||||
d += e
|
||||
}
|
||||
return d, e
|
||||
}
|
||||
|
||||
func NoFix32B(divd int32) (int32, int32) {
|
||||
var d int32
|
||||
var e int32
|
||||
var divr int32 = -1
|
||||
if divd > -2147483648 {
|
||||
// amd64:-"JMP"
|
||||
// 386:-"JMP"
|
||||
d = divd / divr
|
||||
// amd64:-"JMP"
|
||||
// 386:-"JMP"
|
||||
e = divd % divr
|
||||
d += e
|
||||
}
|
||||
return d, e
|
||||
}
|
||||
|
||||
func NoFix16A(divr int16) (int16, int16) {
|
||||
var d int16 = 42
|
||||
var e int16 = 84
|
||||
if divr > 5 {
|
||||
// amd64:-"JMP"
|
||||
// 386:-"JMP"
|
||||
d /= divr
|
||||
// amd64:-"JMP"
|
||||
// 386:-"JMP"
|
||||
e %= divr
|
||||
d += e
|
||||
}
|
||||
return d, e
|
||||
}
|
||||
|
||||
func NoFix16B(divd int16) (int16, int16) {
|
||||
var d int16
|
||||
var e int16
|
||||
var divr int16 = -1
|
||||
if divd > -32768 {
|
||||
// amd64:-"JMP"
|
||||
// 386:-"JMP"
|
||||
d = divd / divr
|
||||
// amd64:-"JMP"
|
||||
// 386:-"JMP"
|
||||
e = divd % divr
|
||||
d += e
|
||||
}
|
||||
return d, e
|
||||
}
|
||||
|
||||
// Check that len() and cap() calls divided by powers of two are
|
||||
// optimized into shifts and ands
|
||||
|
||||
func LenDiv1(a []int) int {
|
||||
// 386:"SHRL [$]10"
|
||||
// amd64:"SHRQ [$]10"
|
||||
// arm64:"LSR [$]10" -"SDIV"
|
||||
// arm:"SRL [$]10" -".*udiv"
|
||||
// ppc64x:"SRD" [$]10"
|
||||
return len(a) / 1024
|
||||
}
|
||||
|
||||
func LenDiv2(s string) int {
|
||||
// 386:"SHRL [$]11"
|
||||
// amd64:"SHRQ [$]11"
|
||||
// arm64:"LSR [$]11" -"SDIV"
|
||||
// arm:"SRL [$]11" -".*udiv"
|
||||
// ppc64x:"SRD [$]11"
|
||||
return len(s) / (4097 >> 1)
|
||||
}
|
||||
|
||||
func LenMod1(a []int) int {
|
||||
// 386:"ANDL [$]1023"
|
||||
// amd64:"ANDL [$]1023"
|
||||
// arm64:"AND [$]1023" -"SDIV"
|
||||
// arm/6:"AND" -".*udiv"
|
||||
// arm/7:"BFC" -".*udiv" -"AND"
|
||||
// ppc64x:"RLDICL"
|
||||
return len(a) % 1024
|
||||
}
|
||||
|
||||
func LenMod2(s string) int {
|
||||
// 386:"ANDL [$]2047"
|
||||
// amd64:"ANDL [$]2047"
|
||||
// arm64:"AND [$]2047" -"SDIV"
|
||||
// arm/6:"AND" -".*udiv"
|
||||
// arm/7:"BFC" -".*udiv" -"AND"
|
||||
// ppc64x:"RLDICL"
|
||||
return len(s) % (4097 >> 1)
|
||||
}
|
||||
|
||||
func CapDiv(a []int) int {
|
||||
// 386:"SHRL [$]12"
|
||||
// amd64:"SHRQ [$]12"
|
||||
// arm64:"LSR [$]12" -"SDIV"
|
||||
// arm:"SRL [$]12" -".*udiv"
|
||||
// ppc64x:"SRD [$]12"
|
||||
return cap(a) / ((1 << 11) + 2048)
|
||||
}
|
||||
|
||||
func CapMod(a []int) int {
|
||||
// 386:"ANDL [$]4095"
|
||||
// amd64:"ANDL [$]4095"
|
||||
// arm64:"AND [$]4095" -"SDIV"
|
||||
// arm/6:"AND" -".*udiv"
|
||||
// arm/7:"BFC" -".*udiv" -"AND"
|
||||
// ppc64x:"RLDICL"
|
||||
return cap(a) % ((1 << 11) + 2048)
|
||||
}
|
||||
|
||||
func AddMul(x int) int {
|
||||
// amd64:"LEAQ 1"
|
||||
return 2*x + 1
|
||||
}
|
||||
|
||||
func AddShift(a, b int) int {
|
||||
// loong64: "ALSLV"
|
||||
return a + (b << 4)
|
||||
}
|
||||
|
||||
func MULA(a, b, c uint32) (uint32, uint32, uint32) {
|
||||
// arm:`MULA`,-`MUL\s`
|
||||
// arm64:`MADDW`,-`MULW`
|
||||
r0 := a*b + c
|
||||
// arm:`MULA`,-`MUL\s`
|
||||
// arm64:`MADDW`,-`MULW`
|
||||
r1 := c*79 + a
|
||||
// arm:`ADD`,-`MULA`,-`MUL\s`
|
||||
// arm64:`ADD`,-`MADD`,-`MULW`
|
||||
// ppc64x:`ADD`,-`MULLD`
|
||||
r2 := b*64 + c
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
func MULS(a, b, c uint32) (uint32, uint32, uint32) {
|
||||
// arm/7:`MULS`,-`MUL\s`
|
||||
// arm/6:`SUB`,`MUL\s`,-`MULS`
|
||||
// arm64:`MSUBW`,-`MULW`
|
||||
r0 := c - a*b
|
||||
// arm/7:`MULS`,-`MUL\s`
|
||||
// arm/6:`SUB`,`MUL\s`,-`MULS`
|
||||
// arm64:`MSUBW`,-`MULW`
|
||||
r1 := a - c*79
|
||||
// arm/7:`SUB`,-`MULS`,-`MUL\s`
|
||||
// arm64:`SUB`,-`MSUBW`,-`MULW`
|
||||
// ppc64x:`SUB`,-`MULLD`
|
||||
r2 := c - b*64
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
func addSpecial(a, b, c uint32) (uint32, uint32, uint32) {
|
||||
// amd64:`INCL`
|
||||
a++
|
||||
// amd64:`DECL`
|
||||
b--
|
||||
// amd64:`SUBL.*-128`
|
||||
c += 128
|
||||
return a, b, c
|
||||
}
|
||||
|
||||
// Divide -> shift rules usually require fixup for negative inputs.
|
||||
// If the input is non-negative, make sure the unsigned form is generated.
|
||||
func divInt(v int64) int64 {
|
||||
if v < 0 {
|
||||
// amd64:`SARQ.*63,`, `SHRQ.*56,`, `SARQ.*8,`
|
||||
return v / 256
|
||||
}
|
||||
// amd64:-`.*SARQ`, `SHRQ.*9,`
|
||||
return v / 512
|
||||
}
|
||||
|
||||
// The reassociate rules "x - (z + C) -> (x - z) - C" and
|
||||
// "(z + C) -x -> C + (z - x)" can optimize the following cases.
|
||||
func constantFold1(i0, j0, i1, j1, i2, j2, i3, j3 int) (int, int, int, int) {
|
||||
// arm64:"SUB" "ADD [$]2"
|
||||
// ppc64x:"SUB" "ADD [$]2"
|
||||
r0 := (i0 + 3) - (j0 + 1)
|
||||
// arm64:"SUB" "SUB [$]4"
|
||||
// ppc64x:"SUB" "ADD [$]-4"
|
||||
r1 := (i1 - 3) - (j1 + 1)
|
||||
// arm64:"SUB" "ADD [$]4"
|
||||
// ppc64x:"SUB" "ADD [$]4"
|
||||
r2 := (i2 + 3) - (j2 - 1)
|
||||
// arm64:"SUB" "SUB [$]2"
|
||||
// ppc64x:"SUB" "ADD [$]-2"
|
||||
r3 := (i3 - 3) - (j3 - 1)
|
||||
return r0, r1, r2, r3
|
||||
}
|
||||
|
||||
// The reassociate rules "x - (z + C) -> (x - z) - C" and
|
||||
// "(C - z) - x -> C - (z + x)" can optimize the following cases.
|
||||
func constantFold2(i0, j0, i1, j1 int) (int, int) {
|
||||
// arm64:"ADD" "MOVD [$]2" "SUB"
|
||||
// ppc64x: `SUBC R[0-9]+,\s[$]2,\sR`
|
||||
r0 := (3 - i0) - (j0 + 1)
|
||||
// arm64:"ADD" "MOVD [$]4" "SUB"
|
||||
// ppc64x: `SUBC R[0-9]+,\s[$]4,\sR`
|
||||
r1 := (3 - i1) - (j1 - 1)
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func constantFold3(i, j int) int {
|
||||
// arm64: "LSL [$]5," "SUB R[0-9]+<<1," -"ADD"
|
||||
// ppc64x:"MULLD [$]30" "MULLD"
|
||||
r := (5 * i) * (6 * j)
|
||||
return r
|
||||
}
|
||||
|
||||
// Integer Min/Max
|
||||
|
||||
func Int64Min(a, b int64) int64 {
|
||||
// amd64: "CMPQ" "CMOVQLT"
|
||||
// arm64: "CMP" "CSEL"
|
||||
// riscv64/rva20u64:"BLT "
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"MIN "
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func Int64Max(a, b int64) int64 {
|
||||
// amd64: "CMPQ" "CMOVQGT"
|
||||
// arm64: "CMP" "CSEL"
|
||||
// riscv64/rva20u64:"BLT "
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"MAX "
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
func Uint64Min(a, b uint64) uint64 {
|
||||
// amd64: "CMPQ" "CMOVQCS"
|
||||
// arm64: "CMP" "CSEL"
|
||||
// riscv64/rva20u64:"BLTU"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"MINU"
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func Uint64Max(a, b uint64) uint64 {
|
||||
// amd64: "CMPQ" "CMOVQHI"
|
||||
// arm64: "CMP" "CSEL"
|
||||
// riscv64/rva20u64:"BLTU"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"MAXU"
|
||||
return max(a, b)
|
||||
}
|
||||
95
test/codegen/atomics.go
Normal file
95
test/codegen/atomics.go
Normal file
@@ -0,0 +1,95 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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.
|
||||
|
||||
// These tests check that atomic instructions without dynamic checks are
|
||||
// generated for architectures that support them
|
||||
|
||||
package codegen
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
type Counter struct {
|
||||
count int32
|
||||
}
|
||||
|
||||
func (c *Counter) Increment() {
|
||||
// Check that ARm64 v8.0 has both atomic instruction (LDADDALW) and a dynamic check
|
||||
// (for arm64HasATOMICS), while ARM64 v8.1 has only atomic and no dynamic check.
|
||||
// arm64/v8.0:"LDADDALW"
|
||||
// arm64/v8.1:"LDADDALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK" -"CMPXCHG"
|
||||
atomic.AddInt32(&c.count, 1)
|
||||
}
|
||||
|
||||
func atomicLogical64(x *atomic.Uint64) uint64 {
|
||||
var r uint64
|
||||
|
||||
// arm64/v8.0:"LDCLRALD"
|
||||
// arm64/v8.1:"LDCLRALD"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// On amd64, make sure we use LOCK+AND instead of CMPXCHG when we don't use the result.
|
||||
// amd64:"LOCK" -"CMPXCHGQ"
|
||||
x.And(11)
|
||||
// arm64/v8.0:"LDCLRALD"
|
||||
// arm64/v8.1:"LDCLRALD"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK" "CMPXCHGQ"
|
||||
r += x.And(22)
|
||||
|
||||
// arm64/v8.0:"LDORALD"
|
||||
// arm64/v8.1:"LDORALD"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// On amd64, make sure we use LOCK+OR instead of CMPXCHG when we don't use the result.
|
||||
// amd64:"LOCK" -"CMPXCHGQ"
|
||||
x.Or(33)
|
||||
// arm64/v8.0:"LDORALD"
|
||||
// arm64/v8.1:"LDORALD"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK" "CMPXCHGQ"
|
||||
r += x.Or(44)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func atomicLogical32(x *atomic.Uint32) uint32 {
|
||||
var r uint32
|
||||
|
||||
// arm64/v8.0:"LDCLRALW"
|
||||
// arm64/v8.1:"LDCLRALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// On amd64, make sure we use LOCK+AND instead of CMPXCHG when we don't use the result.
|
||||
// amd64:"LOCK" -"CMPXCHGL"
|
||||
x.And(11)
|
||||
// arm64/v8.0:"LDCLRALW"
|
||||
// arm64/v8.1:"LDCLRALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK" "CMPXCHGL"
|
||||
r += x.And(22)
|
||||
|
||||
// arm64/v8.0:"LDORALW"
|
||||
// arm64/v8.1:"LDORALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// On amd64, make sure we use LOCK+OR instead of CMPXCHG when we don't use the result.
|
||||
// amd64:"LOCK" -"CMPXCHGL"
|
||||
x.Or(33)
|
||||
// arm64/v8.0:"LDORALW"
|
||||
// arm64/v8.1:"LDORALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK" "CMPXCHGL"
|
||||
r += x.Or(44)
|
||||
|
||||
return r
|
||||
}
|
||||
378
test/codegen/bitfield.go
Normal file
378
test/codegen/bitfield.go
Normal file
@@ -0,0 +1,378 @@
|
||||
// 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
|
||||
|
||||
// This file contains codegen tests related to bit field
|
||||
// insertion/extraction simplifications/optimizations.
|
||||
|
||||
func extr1(x, x2 uint64) uint64 {
|
||||
return x<<7 + x2>>57 // arm64:"EXTR [$]57,"
|
||||
}
|
||||
|
||||
func extr2(x, x2 uint64) uint64 {
|
||||
return x<<7 | x2>>57 // arm64:"EXTR [$]57,"
|
||||
}
|
||||
|
||||
func extr3(x, x2 uint64) uint64 {
|
||||
return x<<7 ^ x2>>57 // arm64:"EXTR [$]57,"
|
||||
}
|
||||
|
||||
func extr4(x, x2 uint32) uint32 {
|
||||
return x<<7 + x2>>25 // arm64:"EXTRW [$]25,"
|
||||
}
|
||||
|
||||
func extr5(x, x2 uint32) uint32 {
|
||||
return x<<7 | x2>>25 // arm64:"EXTRW [$]25,"
|
||||
}
|
||||
|
||||
func extr6(x, x2 uint32) uint32 {
|
||||
return x<<7 ^ x2>>25 // arm64:"EXTRW [$]25,"
|
||||
}
|
||||
|
||||
// check 32-bit shift masking
|
||||
func mask32(x uint32) uint32 {
|
||||
return (x << 29) >> 29 // arm64:"AND [$]7, R[0-9]+" -"LSR" -"LSL"
|
||||
}
|
||||
|
||||
// check 16-bit shift masking
|
||||
func mask16(x uint16) uint16 {
|
||||
return (x << 14) >> 14 // arm64:"AND [$]3, R[0-9]+" -"LSR" -"LSL"
|
||||
}
|
||||
|
||||
// check 8-bit shift masking
|
||||
func mask8(x uint8) uint8 {
|
||||
return (x << 7) >> 7 // arm64:"AND [$]1, R[0-9]+" -"LSR" -"LSL"
|
||||
}
|
||||
|
||||
func maskshift(x uint64) uint64 {
|
||||
// arm64:"AND [$]4095, R[0-9]+" -"LSL" -"LSR" -"UBFIZ" -"UBFX"
|
||||
return ((x << 5) & (0xfff << 5)) >> 5
|
||||
}
|
||||
|
||||
// bitfield ops
|
||||
// bfi
|
||||
func bfi1(x, y uint64) uint64 {
|
||||
// arm64:"BFI [$]4, R[0-9]+, [$]12" -"LSL" -"LSR" -"AND"
|
||||
return ((x & 0xfff) << 4) | (y & 0xffffffffffff000f)
|
||||
}
|
||||
|
||||
func bfi2(x, y uint64) uint64 {
|
||||
// arm64:"BFI [$]12, R[0-9]+, [$]40" -"LSL" -"LSR" -"AND"
|
||||
return (x << 24 >> 12) | (y & 0xfff0000000000fff)
|
||||
}
|
||||
|
||||
// bfxil
|
||||
func bfxil1(x, y uint64) uint64 {
|
||||
// arm64:"BFXIL [$]5, R[0-9]+, [$]12" -"LSL" -"LSR" -"AND"
|
||||
return ((x >> 5) & 0xfff) | (y & 0xfffffffffffff000)
|
||||
}
|
||||
|
||||
func bfxil2(x, y uint64) uint64 {
|
||||
// arm64:"BFXIL [$]12, R[0-9]+, [$]40" -"LSL" -"LSR" -"AND"
|
||||
return (x << 12 >> 24) | (y & 0xffffff0000000000)
|
||||
}
|
||||
|
||||
// sbfiz
|
||||
// merge shifts into sbfiz: (x << lc) >> rc && lc > rc.
|
||||
func sbfiz1(x int64) int64 {
|
||||
// arm64:"SBFIZ [$]1, R[0-9]+, [$]60" -"LSL" -"ASR"
|
||||
return (x << 4) >> 3
|
||||
}
|
||||
|
||||
// merge shift and sign-extension into sbfiz.
|
||||
func sbfiz2(x int32) int64 {
|
||||
return int64(x << 3) // arm64:"SBFIZ [$]3, R[0-9]+, [$]29" -"LSL"
|
||||
}
|
||||
|
||||
func sbfiz3(x int16) int64 {
|
||||
return int64(x << 3) // arm64:"SBFIZ [$]3, R[0-9]+, [$]13" -"LSL"
|
||||
}
|
||||
|
||||
func sbfiz4(x int8) int64 {
|
||||
return int64(x << 3) // arm64:"SBFIZ [$]3, R[0-9]+, [$]5" -"LSL"
|
||||
}
|
||||
|
||||
// sbfiz combinations.
|
||||
// merge shift with sbfiz into sbfiz.
|
||||
func sbfiz5(x int32) int32 {
|
||||
// arm64:"SBFIZ [$]1, R[0-9]+, [$]28" -"LSL" -"ASR"
|
||||
return (x << 4) >> 3
|
||||
}
|
||||
|
||||
func sbfiz6(x int16) int64 {
|
||||
return int64(x+1) << 3 // arm64:"SBFIZ [$]3, R[0-9]+, [$]16" -"LSL"
|
||||
}
|
||||
|
||||
func sbfiz7(x int8) int64 {
|
||||
return int64(x+1) << 62 // arm64:"SBFIZ [$]62, R[0-9]+, [$]2" -"LSL"
|
||||
}
|
||||
|
||||
func sbfiz8(x int32) int64 {
|
||||
return int64(x+1) << 40 // arm64:"SBFIZ [$]40, R[0-9]+, [$]24" -"LSL"
|
||||
}
|
||||
|
||||
// sbfx
|
||||
// merge shifts into sbfx: (x << lc) >> rc && lc <= rc.
|
||||
func sbfx1(x int64) int64 {
|
||||
return (x << 3) >> 4 // arm64:"SBFX [$]1, R[0-9]+, [$]60" -"LSL" -"ASR"
|
||||
}
|
||||
|
||||
func sbfx2(x int64) int64 {
|
||||
return (x << 60) >> 60 // arm64:"SBFX [$]0, R[0-9]+, [$]4" -"LSL" -"ASR"
|
||||
}
|
||||
|
||||
// merge shift and sign-extension into sbfx.
|
||||
func sbfx3(x int32) int64 {
|
||||
return int64(x) >> 3 // arm64:"SBFX [$]3, R[0-9]+, [$]29" -"ASR"
|
||||
}
|
||||
|
||||
func sbfx4(x int16) int64 {
|
||||
return int64(x) >> 3 // arm64:"SBFX [$]3, R[0-9]+, [$]13" -"ASR"
|
||||
}
|
||||
|
||||
func sbfx5(x int8) int64 {
|
||||
return int64(x) >> 3 // arm64:"SBFX [$]3, R[0-9]+, [$]5" -"ASR"
|
||||
}
|
||||
|
||||
func sbfx6(x int32) int64 {
|
||||
return int64(x >> 30) // arm64:"SBFX [$]30, R[0-9]+, [$]2"
|
||||
}
|
||||
|
||||
func sbfx7(x int16) int64 {
|
||||
return int64(x >> 10) // arm64:"SBFX [$]10, R[0-9]+, [$]6"
|
||||
}
|
||||
|
||||
func sbfx8(x int8) int64 {
|
||||
return int64(x >> 5) // arm64:"SBFX [$]5, R[0-9]+, [$]3"
|
||||
}
|
||||
|
||||
// sbfx combinations.
|
||||
// merge shifts with sbfiz into sbfx.
|
||||
func sbfx9(x int32) int32 {
|
||||
return (x << 3) >> 4 // arm64:"SBFX [$]1, R[0-9]+, [$]28" -"LSL" -"ASR"
|
||||
}
|
||||
|
||||
// merge sbfx and sign-extension into sbfx.
|
||||
func sbfx10(x int32) int64 {
|
||||
c := x + 5
|
||||
return int64(c >> 20) // arm64"SBFX [$]20, R[0-9]+, [$]12" -"MOVW R[0-9]+, R[0-9]+"
|
||||
}
|
||||
|
||||
// ubfiz
|
||||
// merge shifts into ubfiz: (x<<lc)>>rc && lc>rc
|
||||
func ubfiz1(x uint64) uint64 {
|
||||
// arm64:"UBFIZ [$]1, R[0-9]+, [$]60" -"LSL" -"LSR"
|
||||
// s390x:"RISBGZ [$]3, [$]62, [$]1, " -"SLD" -"SRD"
|
||||
return (x << 4) >> 3
|
||||
}
|
||||
|
||||
// merge shift and zero-extension into ubfiz.
|
||||
func ubfiz2(x uint32) uint64 {
|
||||
return uint64(x+1) << 3 // arm64:"UBFIZ [$]3, R[0-9]+, [$]32" -"LSL"
|
||||
}
|
||||
|
||||
func ubfiz3(x uint16) uint64 {
|
||||
return uint64(x+1) << 3 // arm64:"UBFIZ [$]3, R[0-9]+, [$]16" -"LSL"
|
||||
}
|
||||
|
||||
func ubfiz4(x uint8) uint64 {
|
||||
return uint64(x+1) << 3 // arm64:"UBFIZ [$]3, R[0-9]+, [$]8" -"LSL"
|
||||
}
|
||||
|
||||
func ubfiz5(x uint8) uint64 {
|
||||
return uint64(x) << 60 // arm64:"UBFIZ [$]60, R[0-9]+, [$]4" -"LSL"
|
||||
}
|
||||
|
||||
func ubfiz6(x uint32) uint64 {
|
||||
return uint64(x << 30) // arm64:"UBFIZ [$]30, R[0-9]+, [$]2",
|
||||
}
|
||||
|
||||
func ubfiz7(x uint16) uint64 {
|
||||
return uint64(x << 10) // arm64:"UBFIZ [$]10, R[0-9]+, [$]6",
|
||||
}
|
||||
|
||||
func ubfiz8(x uint8) uint64 {
|
||||
return uint64(x << 7) // arm64:"UBFIZ [$]7, R[0-9]+, [$]1",
|
||||
}
|
||||
|
||||
// merge ANDconst into ubfiz.
|
||||
func ubfiz9(x uint64) uint64 {
|
||||
// arm64:"UBFIZ [$]3, R[0-9]+, [$]12" -"LSL" -"AND"
|
||||
// s390x:"RISBGZ [$]49, [$]60, [$]3," -"SLD" -"AND"
|
||||
return (x & 0xfff) << 3
|
||||
}
|
||||
|
||||
func ubfiz10(x uint64) uint64 {
|
||||
// arm64:"UBFIZ [$]4, R[0-9]+, [$]12" -"LSL" -"AND"
|
||||
// s390x:"RISBGZ [$]48, [$]59, [$]4," -"SLD" -"AND"
|
||||
return (x << 4) & 0xfff0
|
||||
}
|
||||
|
||||
// ubfiz combinations
|
||||
func ubfiz11(x uint32) uint32 {
|
||||
// arm64:"UBFIZ [$]1, R[0-9]+, [$]28" -"LSL" -"LSR"
|
||||
return (x << 4) >> 3
|
||||
}
|
||||
|
||||
func ubfiz12(x uint64) uint64 {
|
||||
// arm64:"UBFIZ [$]1, R[0-9]+, [$]20" -"LSL" -"LSR"
|
||||
// s390x:"RISBGZ [$]43, [$]62, [$]1, " -"SLD" -"SRD" -"AND"
|
||||
return ((x & 0xfffff) << 4) >> 3
|
||||
}
|
||||
|
||||
func ubfiz13(x uint64) uint64 {
|
||||
// arm64:"UBFIZ [$]5, R[0-9]+, [$]13" -"LSL" -"LSR" -"AND"
|
||||
return ((x << 3) & 0xffff) << 2
|
||||
}
|
||||
|
||||
func ubfiz14(x uint64) uint64 {
|
||||
// arm64:"UBFIZ [$]7, R[0-9]+, [$]12" -"LSL" -"LSR" -"AND"
|
||||
// s390x:"RISBGZ [$]45, [$]56, [$]7, " -"SLD" -"SRD" -"AND"
|
||||
return ((x << 5) & (0xfff << 5)) << 2
|
||||
}
|
||||
|
||||
// ubfx
|
||||
// merge shifts into ubfx: (x<<lc)>>rc && lc<rc
|
||||
func ubfx1(x uint64) uint64 {
|
||||
// arm64:"UBFX [$]1, R[0-9]+, [$]62" -"LSL" -"LSR"
|
||||
// s390x:"RISBGZ [$]2, [$]63, [$]63," -"SLD" -"SRD"
|
||||
return (x << 1) >> 2
|
||||
}
|
||||
|
||||
// merge shift and zero-extension into ubfx.
|
||||
func ubfx2(x uint32) uint64 {
|
||||
return uint64(x >> 15) // arm64:"UBFX [$]15, R[0-9]+, [$]17" -"LSR"
|
||||
}
|
||||
|
||||
func ubfx3(x uint16) uint64 {
|
||||
return uint64(x >> 9) // arm64:"UBFX [$]9, R[0-9]+, [$]7" -"LSR"
|
||||
}
|
||||
|
||||
func ubfx4(x uint8) uint64 {
|
||||
return uint64(x >> 3) // arm64:"UBFX [$]3, R[0-9]+, [$]5" -"LSR"
|
||||
}
|
||||
|
||||
func ubfx5(x uint32) uint64 {
|
||||
return uint64(x) >> 30 // arm64:"UBFX [$]30, R[0-9]+, [$]2"
|
||||
}
|
||||
|
||||
func ubfx6(x uint16) uint64 {
|
||||
return uint64(x) >> 10 // arm64:"UBFX [$]10, R[0-9]+, [$]6"
|
||||
}
|
||||
|
||||
func ubfx7(x uint8) uint64 {
|
||||
return uint64(x) >> 3 // arm64:"UBFX [$]3, R[0-9]+, [$]5"
|
||||
}
|
||||
|
||||
// merge ANDconst into ubfx.
|
||||
func ubfx8(x uint64) uint64 {
|
||||
// arm64:"UBFX [$]25, R[0-9]+, [$]10" -"LSR" -"AND"
|
||||
// s390x:"RISBGZ [$]54, [$]63, [$]39, " -"SRD" -"AND"
|
||||
return (x >> 25) & 1023
|
||||
}
|
||||
|
||||
func ubfx9(x uint64) uint64 {
|
||||
// arm64:"UBFX [$]4, R[0-9]+, [$]8" -"LSR" -"AND"
|
||||
// s390x:"RISBGZ [$]56, [$]63, [$]60, " -"SRD" -"AND"
|
||||
return (x & 0x0ff0) >> 4
|
||||
}
|
||||
|
||||
// ubfx combinations.
|
||||
func ubfx10(x uint32) uint32 {
|
||||
// arm64:"UBFX [$]1, R[0-9]+, [$]30" -"LSL" -"LSR"
|
||||
return (x << 1) >> 2
|
||||
}
|
||||
|
||||
func ubfx11(x uint64) uint64 {
|
||||
// arm64:"UBFX [$]1, R[0-9]+, [$]12" -"LSL" -"LSR" -"AND"
|
||||
// s390x:"RISBGZ [$]52, [$]63, [$]63," -"SLD" -"SRD" -"AND"
|
||||
return ((x << 1) >> 2) & 0xfff
|
||||
}
|
||||
|
||||
func ubfx12(x uint64) uint64 {
|
||||
// arm64:"UBFX [$]4, R[0-9]+, [$]11" -"LSL" -"LSR" -"AND"
|
||||
// s390x:"RISBGZ [$]53, [$]63, [$]60, " -"SLD" -"SRD" -"AND"
|
||||
return ((x >> 3) & 0xfff) >> 1
|
||||
}
|
||||
|
||||
func ubfx13(x uint64) uint64 {
|
||||
// arm64:"UBFX [$]5, R[0-9]+, [$]56" -"LSL" -"LSR"
|
||||
// s390x:"RISBGZ [$]8, [$]63, [$]59, " -"SLD" -"SRD"
|
||||
return ((x >> 2) << 5) >> 8
|
||||
}
|
||||
|
||||
func ubfx14(x uint64) uint64 {
|
||||
// arm64:"UBFX [$]1, R[0-9]+, [$]19" -"LSL" -"LSR"
|
||||
// s390x:"RISBGZ [$]45, [$]63, [$]63, " -"SLD" -"SRD" -"AND"
|
||||
return ((x & 0xfffff) << 3) >> 4
|
||||
}
|
||||
|
||||
// merge ubfx and zero-extension into ubfx.
|
||||
func ubfx15(x uint64) bool {
|
||||
midr := x + 10
|
||||
part_num := uint16((midr >> 4) & 0xfff)
|
||||
if part_num == 0xd0c { // arm64:"UBFX [$]4, R[0-9]+, [$]12" -"MOVHU R[0-9]+, R[0-9]+"
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// merge ANDconst and ubfx into ubfx
|
||||
func ubfx16(x uint64) uint64 {
|
||||
// arm64:"UBFX [$]4, R[0-9]+, [$]6" -"AND [$]63"
|
||||
return ((x >> 3) & 0xfff) >> 1 & 0x3f
|
||||
}
|
||||
|
||||
// Check that we don't emit comparisons for constant shifts.
|
||||
//
|
||||
//go:nosplit
|
||||
func shift_no_cmp(x int) int {
|
||||
// arm64:`LSL [$]17`,-`CMP`
|
||||
// mips64:`SLLV [$]17`,-`SGT`
|
||||
return x << 17
|
||||
}
|
||||
|
||||
func rev16(c uint64) (uint64, uint64, uint64) {
|
||||
// arm64:`REV16`,-`AND`,-`LSR`,-`AND`,-`ORR R[0-9]+<<8`
|
||||
// loong64:`REVB4H`,-`MOVV`,-`AND`,-`SRLV`,-`AND`,-`SLLV`,-`OR`
|
||||
b1 := ((c & 0xff00ff00ff00ff00) >> 8) | ((c & 0x00ff00ff00ff00ff) << 8)
|
||||
// arm64:-`ADD R[0-9]+<<8`
|
||||
// loong64:-`ADDV`
|
||||
b2 := ((c & 0xff00ff00ff00ff00) >> 8) + ((c & 0x00ff00ff00ff00ff) << 8)
|
||||
// arm64:-`EOR R[0-9]+<<8`
|
||||
// loong64:-`XOR`
|
||||
b3 := ((c & 0xff00ff00ff00ff00) >> 8) ^ ((c & 0x00ff00ff00ff00ff) << 8)
|
||||
return b1, b2, b3
|
||||
}
|
||||
|
||||
func rev16w(c uint32) (uint32, uint32, uint32) {
|
||||
// arm64:`REV16W`,-`AND`,-`UBFX`,-`AND`,-`ORR R[0-9]+<<8`
|
||||
// loong64:`REVB2H`,-`AND`,-`SRL`,-`AND`,-`SLL`,-`OR`
|
||||
b1 := ((c & 0xff00ff00) >> 8) | ((c & 0x00ff00ff) << 8)
|
||||
// arm64:-`ADD R[0-9]+<<8`
|
||||
// loong64:-`ADDV`
|
||||
b2 := ((c & 0xff00ff00) >> 8) + ((c & 0x00ff00ff) << 8)
|
||||
// arm64:-`EOR R[0-9]+<<8`
|
||||
// loong64:-`XOR`
|
||||
b3 := ((c & 0xff00ff00) >> 8) ^ ((c & 0x00ff00ff) << 8)
|
||||
return b1, b2, b3
|
||||
}
|
||||
|
||||
func shift(x uint32, y uint16, z uint8) uint64 {
|
||||
// arm64:-`MOVWU`,-`LSR [$]32`
|
||||
// loong64:-`MOVWU`,-`SRLV [$]32`
|
||||
a := uint64(x) >> 32
|
||||
// arm64:-`MOVHU
|
||||
// loong64:-`MOVHU`,-`SRLV [$]16`
|
||||
b := uint64(y) >> 16
|
||||
// arm64:-`MOVBU`
|
||||
// loong64:-`MOVBU`,-`SRLV [$]8`
|
||||
c := uint64(z) >> 8
|
||||
// arm64:`MOVD ZR`,-`ADD R[0-9]+>>16`,-`ADD R[0-9]+>>8`,
|
||||
// loong64:`MOVV R0`,-`ADDVU`
|
||||
return a + b + c
|
||||
}
|
||||
565
test/codegen/bits.go
Normal file
565
test/codegen/bits.go
Normal file
@@ -0,0 +1,565 @@
|
||||
// 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 "math/bits"
|
||||
|
||||
//
|
||||
// 64 bit instructions
|
||||
//
|
||||
|
||||
func bitsCheckConstLeftShiftU64(a uint64) (n int) {
|
||||
// amd64:"BTQ [$]63,"
|
||||
// arm64:"TBNZ [$]63,"
|
||||
// riscv64:"MOV [$]" "AND" "BNEZ"
|
||||
if a&(1<<63) != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTQ [$]60,"
|
||||
// arm64:"TBNZ [$]60,"
|
||||
// riscv64:"MOV [$]" "AND" "BNEZ"
|
||||
if a&(1<<60) != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]0,"
|
||||
// arm64:"TBZ [$]0,"
|
||||
// riscv64:"ANDI" "BEQZ"
|
||||
if a&(1<<0) != 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bitsCheckConstRightShiftU64(a [8]uint64) (n int) {
|
||||
// amd64:"BTQ [$]63,"
|
||||
// arm64:"LSR [$]63," "TBNZ [$]0,"
|
||||
// riscv64:"SRLI" "ANDI" "BNEZ"
|
||||
if (a[0]>>63)&1 != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTQ [$]63,"
|
||||
// arm64:"LSR [$]63," "CBNZ"
|
||||
// riscv64:"SRLI" "BNEZ"
|
||||
if a[1]>>63 != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTQ [$]63,"
|
||||
// arm64:"LSR [$]63," "CBZ"
|
||||
// riscv64:"SRLI" "BEQZ"
|
||||
if a[2]>>63 == 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTQ [$]60,"
|
||||
// arm64:"LSR [$]60," "TBZ [$]0,"
|
||||
// riscv64:"SRLI", "ANDI" "BEQZ"
|
||||
if (a[3]>>60)&1 == 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]1,"
|
||||
// arm64:"LSR [$]1," "TBZ [$]0,"
|
||||
// riscv64:"SRLI" "ANDI" "BEQZ"
|
||||
if (a[4]>>1)&1 == 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]0,"
|
||||
// arm64:"TBZ [$]0," -"LSR"
|
||||
// riscv64:"ANDI" "BEQZ" -"SRLI"
|
||||
if (a[5]>>0)&1 == 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]7,"
|
||||
// arm64:"LSR [$]5," "TBNZ [$]2,"
|
||||
// riscv64:"SRLI" "ANDI" "BNEZ"
|
||||
if (a[6]>>5)&4 == 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bitsCheckVarU64(a, b uint64) (n int) {
|
||||
// amd64:"BTQ"
|
||||
// arm64:"MOVD [$]1," "LSL" "TST"
|
||||
// riscv64:"ANDI [$]63," "SLL " "AND "
|
||||
if a&(1<<(b&63)) != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTQ" -"BT. [$]0,"
|
||||
// arm64:"LSR" "TBZ [$]0,"
|
||||
// riscv64:"ANDI [$]63," "SRL" "ANDI [$]1,"
|
||||
if (b>>(a&63))&1 != 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bitsCheckMaskU64(a uint64) (n int) {
|
||||
// amd64:"BTQ [$]63,"
|
||||
// arm64:"TBNZ [$]63,"
|
||||
// riscv64:"MOV [$]" "AND" "BNEZ"
|
||||
if a&0x8000000000000000 != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTQ [$]59,"
|
||||
// arm64:"TBNZ [$]59,"
|
||||
// riscv64:"MOV [$]" "AND" "BNEZ"
|
||||
if a&0x800000000000000 != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]0,"
|
||||
// arm64:"TBZ [$]0,"
|
||||
// riscv64:"ANDI" "BEQZ"
|
||||
if a&0x1 != 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bitsSetU64(a, b uint64) (n uint64) {
|
||||
// amd64:"BTSQ"
|
||||
// arm64:"MOVD [$]1," "LSL" "ORR"
|
||||
// riscv64:"ANDI" "SLL" "OR"
|
||||
n += b | (1 << (a & 63))
|
||||
|
||||
// amd64:"BTSQ [$]63,"
|
||||
// arm64:"ORR [$]-9223372036854775808,"
|
||||
// riscv64:"MOV [$]" "OR "
|
||||
n += a | (1 << 63)
|
||||
|
||||
// amd64:"BTSQ [$]60,"
|
||||
// arm64:"ORR [$]1152921504606846976,"
|
||||
// riscv64:"MOV [$]" "OR "
|
||||
n += a | (1 << 60)
|
||||
|
||||
// amd64:"ORQ [$]1,"
|
||||
// arm64:"ORR [$]1,"
|
||||
// riscv64:"ORI"
|
||||
n += a | (1 << 0)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func bitsClearU64(a, b uint64) (n uint64) {
|
||||
// amd64:"BTRQ"
|
||||
// arm64:"MOVD [$]1," "LSL" "BIC"
|
||||
// riscv64:"ANDI" "SLL" "ANDN"
|
||||
n += b &^ (1 << (a & 63))
|
||||
|
||||
// amd64:"BTRQ [$]63,"
|
||||
// arm64:"AND [$]9223372036854775807,"
|
||||
// riscv64:"MOV [$]" "AND "
|
||||
n += a &^ (1 << 63)
|
||||
|
||||
// amd64:"BTRQ [$]60,"
|
||||
// arm64:"AND [$]-1152921504606846977,"
|
||||
// riscv64:"MOV [$]" "AND "
|
||||
n += a &^ (1 << 60)
|
||||
|
||||
// amd64:"ANDQ [$]-2"
|
||||
// arm64:"AND [$]-2"
|
||||
// riscv64:"ANDI [$]-2"
|
||||
n += a &^ (1 << 0)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func bitsClearLowest(x int64, y int32) (int64, int32) {
|
||||
// amd64:"ANDQ [$]-2,"
|
||||
// arm64:"AND [$]-2,"
|
||||
// riscv64:"ANDI [$]-2,"
|
||||
a := (x >> 1) << 1
|
||||
|
||||
// amd64:"ANDL [$]-2,"
|
||||
// arm64:"AND [$]-2,"
|
||||
// riscv64:"ANDI [$]-2,"
|
||||
b := (y >> 1) << 1
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
func bitsFlipU64(a, b uint64) (n uint64) {
|
||||
// amd64:"BTCQ"
|
||||
// arm64:"MOVD [$]1," "LSL" "EOR"
|
||||
// riscv64:"ANDI" "SLL" "XOR "
|
||||
n += b ^ (1 << (a & 63))
|
||||
|
||||
// amd64:"BTCQ [$]63,"
|
||||
// arm64:"EOR [$]-9223372036854775808,"
|
||||
// riscv64:"MOV [$]" "XOR "
|
||||
n += a ^ (1 << 63)
|
||||
|
||||
// amd64:"BTCQ [$]60,"
|
||||
// arm64:"EOR [$]1152921504606846976,"
|
||||
// riscv64:"MOV [$]" "XOR "
|
||||
n += a ^ (1 << 60)
|
||||
|
||||
// amd64:"XORQ [$]1,"
|
||||
// arm64:"EOR [$]1,"
|
||||
// riscv64:"XORI [$]1,"
|
||||
n += a ^ (1 << 0)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
//
|
||||
// 32 bit instructions
|
||||
//
|
||||
|
||||
func bitsCheckConstShiftLeftU32(a uint32) (n int) {
|
||||
// amd64:"BTL [$]31,"
|
||||
// arm64:"TBNZ [$]31,"
|
||||
// riscv64:"MOV [$]" "AND" "BNEZ"
|
||||
if a&(1<<31) != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]28,"
|
||||
// arm64:"TBNZ [$]28,"
|
||||
// riscv64:"ANDI" "BNEZ"
|
||||
if a&(1<<28) != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]0,"
|
||||
// arm64:"TBZ [$]0,"
|
||||
// riscv64:"ANDI" "BEQZ"
|
||||
if a&(1<<0) != 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bitsCheckConstRightShiftU32(a [8]uint32) (n int) {
|
||||
// amd64:"BTL [$]31,"
|
||||
// arm64:"UBFX [$]31," "CBNZW"
|
||||
// riscv64:"SRLI" "ANDI" "BNEZ"
|
||||
if (a[0]>>31)&1 != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]31,"
|
||||
// arm64:"UBFX [$]31," "CBNZW"
|
||||
// riscv64:"SRLI" "BNEZ"
|
||||
if a[1]>>31 != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]31,"
|
||||
// arm64:"UBFX [$]31," "CBZW"
|
||||
// riscv64:"SRLI" "BEQZ"
|
||||
if a[2]>>31 == 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]28,"
|
||||
// arm64:"UBFX [$]28," "TBZ"
|
||||
// riscv64:"SRLI" "ANDI" "BEQZ"
|
||||
if (a[3]>>28)&1 == 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]1,"
|
||||
// arm64:"UBFX [$]1," "TBZ"
|
||||
// riscv64:"SRLI" "ANDI" "BEQZ"
|
||||
if (a[4]>>1)&1 == 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]0,"
|
||||
// arm64:"TBZ" -"UBFX" -"SRL"
|
||||
// riscv64:"ANDI" "BEQZ" -"SRLI "
|
||||
if (a[5]>>0)&1 == 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]7,"
|
||||
// arm64:"UBFX [$]5," "TBNZ"
|
||||
// riscv64:"SRLI" "ANDI" "BNEZ"
|
||||
if (a[6]>>5)&4 == 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bitsCheckVarU32(a, b uint32) (n int) {
|
||||
// amd64:"BTL"
|
||||
// arm64:"AND [$]31," "MOVD [$]1," "LSL" "TSTW"
|
||||
// riscv64:"ANDI [$]31," "SLL " "AND "
|
||||
if a&(1<<(b&31)) != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL" -"BT. [$]0"
|
||||
// arm64:"AND [$]31," "LSR" "TBZ"
|
||||
// riscv64:"ANDI [$]31," "SRLW " "ANDI [$]1,"
|
||||
if (b>>(a&31))&1 != 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bitsCheckMaskU32(a uint32) (n int) {
|
||||
// amd64:"BTL [$]31,"
|
||||
// arm64:"TBNZ [$]31,"
|
||||
// riscv64:"MOV [$]" "AND" "BNEZ"
|
||||
if a&0x80000000 != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]27,"
|
||||
// arm64:"TBNZ [$]27,"
|
||||
// riscv64:"ANDI" "BNEZ"
|
||||
if a&0x8000000 != 0 {
|
||||
return 1
|
||||
}
|
||||
// amd64:"BTL [$]0,"
|
||||
// arm64:"TBZ [$]0,"
|
||||
// riscv64:"ANDI" "BEQZ"
|
||||
if a&0x1 != 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func bitsSetU32(a, b uint32) (n uint32) {
|
||||
// amd64:"BTSL"
|
||||
// arm64:"AND [$]31," "MOVD [$]1," "LSL" "ORR"
|
||||
// riscv64:"ANDI" "SLL" "OR"
|
||||
n += b | (1 << (a & 31))
|
||||
|
||||
// amd64:"ORL [$]-2147483648,"
|
||||
// arm64:"ORR [$]-2147483648,"
|
||||
// riscv64:"ORI [$]-2147483648,"
|
||||
n += a | (1 << 31)
|
||||
|
||||
// amd64:"ORL [$]268435456,"
|
||||
// arm64:"ORR [$]268435456,"
|
||||
// riscv64:"ORI [$]268435456,"
|
||||
n += a | (1 << 28)
|
||||
|
||||
// amd64:"ORL [$]1,"
|
||||
// arm64:"ORR [$]1,"
|
||||
// riscv64:"ORI [$]1,"
|
||||
n += a | (1 << 0)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func bitsClearU32(a, b uint32) (n uint32) {
|
||||
// amd64:"BTRL"
|
||||
// arm64:"AND [$]31," "MOVD [$]1," "LSL" "BIC"
|
||||
// riscv64:"ANDI" "SLL" "ANDN"
|
||||
n += b &^ (1 << (a & 31))
|
||||
|
||||
// amd64:"ANDL [$]2147483647,"
|
||||
// arm64:"AND [$]2147483647,"
|
||||
// riscv64:"ANDI [$]2147483647,"
|
||||
n += a &^ (1 << 31)
|
||||
|
||||
// amd64:"ANDL [$]-268435457,"
|
||||
// arm64:"AND [$]-268435457,"
|
||||
// riscv64:"ANDI [$]-268435457,"
|
||||
n += a &^ (1 << 28)
|
||||
|
||||
// amd64:"ANDL [$]-2,"
|
||||
// arm64:"AND [$]-2,"
|
||||
// riscv64:"ANDI [$]-2,"
|
||||
n += a &^ (1 << 0)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func bitsFlipU32(a, b uint32) (n uint32) {
|
||||
// amd64:"BTCL"
|
||||
// arm64:"AND [$]31," "MOVD [$]1," "LSL" "EOR"
|
||||
// riscv64:"ANDI" "SLL" "XOR "
|
||||
n += b ^ (1 << (a & 31))
|
||||
|
||||
// amd64:"XORL [$]-2147483648,"
|
||||
// arm64:"EOR [$]-2147483648,"
|
||||
// riscv64:"XORI [$]-2147483648,"
|
||||
n += a ^ (1 << 31)
|
||||
|
||||
// amd64:"XORL [$]268435456,"
|
||||
// arm64:"EOR [$]268435456,"
|
||||
// riscv64:"XORI [$]268435456,"
|
||||
n += a ^ (1 << 28)
|
||||
|
||||
// amd64:"XORL [$]1,"
|
||||
// arm64:"EOR [$]1,"
|
||||
// riscv64:"XORI [$]1,"
|
||||
n += a ^ (1 << 0)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func bitsOpOnMem(a []uint32, b, c, d uint32) {
|
||||
// check direct operation on memory with constant
|
||||
|
||||
// amd64:`ANDL\s[$]200,\s\([A-Z][A-Z0-9]+\)`
|
||||
a[0] &= 200
|
||||
// amd64:`ORL\s[$]220,\s4\([A-Z][A-Z0-9]+\)`
|
||||
a[1] |= 220
|
||||
// amd64:`XORL\s[$]240,\s8\([A-Z][A-Z0-9]+\)`
|
||||
a[2] ^= 240
|
||||
}
|
||||
|
||||
func bitsCheckMostNegative(b uint8) bool {
|
||||
// amd64:"TESTB"
|
||||
// arm64:"TSTW" "CSET"
|
||||
// riscv64:"ANDI [$]128," "SNEZ" -"ADDI"
|
||||
return b&0x80 == 0x80
|
||||
}
|
||||
|
||||
func bitsIssue19857a(a uint64) uint64 {
|
||||
// arm64:`AND `
|
||||
return a & ((1 << 63) - 1)
|
||||
}
|
||||
|
||||
func bitsIssue19857b(a uint64) uint64 {
|
||||
// arm64:`AND `
|
||||
return a & (1 << 63)
|
||||
}
|
||||
|
||||
func bitsIssue19857c(a, b uint32) (uint32, uint32) {
|
||||
// arm/7:`BIC`,-`AND`
|
||||
a &= 0xffffaaaa
|
||||
// arm/7:`BFC`,-`AND`,-`BIC`
|
||||
b &= 0xffc003ff
|
||||
return a, b
|
||||
}
|
||||
|
||||
func bitsAndNot(x, y uint32) uint32 {
|
||||
// arm64:`BIC `,-`AND`
|
||||
// loong64:"ANDN " -"AND "
|
||||
// riscv64:"ANDN" -"AND "
|
||||
return x &^ y
|
||||
}
|
||||
|
||||
func bitsXorNot(x, y, z uint32, a []uint32, n, m uint64) uint64 {
|
||||
// arm64:`EON `,-`EOR`,-`MVN`
|
||||
// riscv64:"XNOR " -"MOV [$]" -"XOR"
|
||||
a[0] = x ^ (y ^ 0xffffffff)
|
||||
|
||||
// arm64:`EON `,-`EOR`,-`MVN`
|
||||
// riscv64:"XNOR" -"XOR"
|
||||
a[1] = ^(y ^ z)
|
||||
|
||||
// arm64:`EON `,-`XOR`
|
||||
// riscv64:"XNOR" -"XOR" -"NOT"
|
||||
a[2] = x ^ ^z
|
||||
|
||||
// arm64:`EON `,-`EOR`,-`MVN`
|
||||
// riscv64:"XNOR" -"MOV [$]" -"XOR"
|
||||
return n ^ (m ^ 0xffffffffffffffff)
|
||||
}
|
||||
|
||||
func bitsOrNot(x, y uint32) uint32 {
|
||||
// arm64:"ORN " -"ORR"
|
||||
// loong64:"ORN" -"OR "
|
||||
// riscv64:"ORN" -"OR "
|
||||
return x | ^y
|
||||
}
|
||||
|
||||
func bitsNotOr(x int64, a []int64) {
|
||||
// loong64: "MOVV [$]0" "NOR R"
|
||||
a[0] = ^(0x1234 | x)
|
||||
// loong64:"NOR" -"XOR"
|
||||
a[1] = (-1) ^ x
|
||||
// loong64: "MOVV [$]-55" -"OR" -"NOR"
|
||||
a[2] = ^(0x12 | 0x34)
|
||||
}
|
||||
|
||||
func bitsSetPowerOf2Test(x int) bool {
|
||||
// amd64:"BTL [$]3"
|
||||
// riscv64:"ANDI [$]8," "SNEZ" -"ADDI"
|
||||
return x&8 == 8
|
||||
}
|
||||
|
||||
func bitsSetTest(x int) bool {
|
||||
// amd64:"ANDL [$]9, AX"
|
||||
// amd64:"CMPQ AX, [$]9"
|
||||
// riscv64:"ANDI [$]9," "ADDI [$]-9," "SEQZ"
|
||||
return x&9 == 9
|
||||
}
|
||||
|
||||
func bitsMaskContiguousOnes64U(x uint64) uint64 {
|
||||
// s390x:"RISBGZ [$]16, [$]47, [$]0,"
|
||||
return x & 0x0000ffffffff0000
|
||||
}
|
||||
|
||||
func bitsMaskContiguousZeroes64U(x uint64) uint64 {
|
||||
// s390x:"RISBGZ [$]48, [$]15, [$]0,"
|
||||
return x & 0xffff00000000ffff
|
||||
}
|
||||
|
||||
func bitsIssue44228a(a []int64, i int) bool {
|
||||
// amd64: "BTQ", -"SHL"
|
||||
return a[i>>6]&(1<<(i&63)) != 0
|
||||
}
|
||||
|
||||
func bitsIssue44228b(a []int32, i int) bool {
|
||||
// amd64: "BTL", -"SHL"
|
||||
return a[i>>5]&(1<<(i&31)) != 0
|
||||
}
|
||||
|
||||
func bitsIssue48467(x, y uint64) uint64 {
|
||||
// arm64: -"NEG"
|
||||
d, borrow := bits.Sub64(x, y, 0)
|
||||
return x - d&(-borrow)
|
||||
}
|
||||
|
||||
func bitsFoldConst(x, y uint64) uint64 {
|
||||
// arm64: "ADDS [$]7" -"MOVD [$]7"
|
||||
// ppc64x: "ADDC [$]7,"
|
||||
d, b := bits.Add64(x, 7, 0)
|
||||
return b & d
|
||||
}
|
||||
|
||||
func bitsFoldConstOutOfRange(a uint64) uint64 {
|
||||
// arm64: "MOVD [$]19088744" -"ADD [$]19088744"
|
||||
return a + 0x1234568
|
||||
}
|
||||
|
||||
func bitsSignExtendAndMask8to64U(a int8) (s, z uint64) {
|
||||
// Verify sign-extended values are not zero-extended under a bit mask (#61297)
|
||||
|
||||
// ppc64x: "MOVB", "ANDCC [$]1015,"
|
||||
s = uint64(a) & 0x3F7
|
||||
// ppc64x: -"MOVB", "ANDCC [$]247,"
|
||||
z = uint64(uint8(a)) & 0x3F7
|
||||
return
|
||||
}
|
||||
|
||||
func bitsZeroExtendAndMask8toU64(a int8, b int16) (x, y uint64) {
|
||||
// Verify zero-extended values are not sign-extended under a bit mask (#61297)
|
||||
|
||||
// ppc64x: -"MOVB ", -"ANDCC", "MOVBZ"
|
||||
x = uint64(a) & 0xFF
|
||||
// ppc64x: -"MOVH ", -"ANDCC", "MOVHZ"
|
||||
y = uint64(b) & 0xFFFF
|
||||
return
|
||||
}
|
||||
|
||||
func bitsRotateAndMask(io64 [8]uint64, io32 [4]uint32, io16 [4]uint16, io8 [4]uint8) {
|
||||
// Verify rotate and mask instructions, and further simplified instructions for small types
|
||||
|
||||
// ppc64x: "RLDICR [$]0, R[0-9]*, [$]47, R"
|
||||
io64[0] = io64[0] & 0xFFFFFFFFFFFF0000
|
||||
// ppc64x: "RLDICL [$]0, R[0-9]*, [$]16, R"
|
||||
io64[1] = io64[1] & 0x0000FFFFFFFFFFFF
|
||||
// ppc64x: -"SRD", -"AND", "RLDICL [$]60, R[0-9]*, [$]16, R"
|
||||
io64[2] = (io64[2] >> 4) & 0x0000FFFFFFFFFFFF
|
||||
// ppc64x: -"SRD", -"AND", "RLDICL [$]36, R[0-9]*, [$]28, R"
|
||||
io64[3] = (io64[3] >> 28) & 0x0000FFFFFFFFFFFF
|
||||
|
||||
// ppc64x: "MOVWZ", "RLWNM [$]1, R[0-9]*, [$]28, [$]3, R"
|
||||
io64[4] = uint64(bits.RotateLeft32(io32[0], 1) & 0xF000000F)
|
||||
|
||||
// ppc64x: "RLWNM [$]0, R[0-9]*, [$]4, [$]19, R"
|
||||
io32[0] = io32[0] & 0x0FFFF000
|
||||
// ppc64x: "RLWNM [$]0, R[0-9]*, [$]20, [$]3, R"
|
||||
io32[1] = io32[1] & 0xF0000FFF
|
||||
// ppc64x: -"RLWNM", MOVD, AND
|
||||
io32[2] = io32[2] & 0xFFFF0002
|
||||
|
||||
var bigc uint32 = 0x12345678
|
||||
// ppc64x: "ANDCC [$]22136"
|
||||
io16[0] = io16[0] & uint16(bigc)
|
||||
|
||||
// ppc64x: "ANDCC [$]120"
|
||||
io8[0] = io8[0] & uint8(bigc)
|
||||
}
|
||||
209
test/codegen/bmi.go
Normal file
209
test/codegen/bmi.go
Normal file
@@ -0,0 +1,209 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2021 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
|
||||
|
||||
func andn64(x, y int64) int64 {
|
||||
// amd64/v3:"ANDNQ"
|
||||
return x &^ y
|
||||
}
|
||||
|
||||
func andn32(x, y int32) int32 {
|
||||
// amd64/v3:"ANDNL"
|
||||
return x &^ y
|
||||
}
|
||||
|
||||
func blsi64(x int64) int64 {
|
||||
// amd64/v3:"BLSIQ"
|
||||
return x & -x
|
||||
}
|
||||
|
||||
func blsi32(x int32) int32 {
|
||||
// amd64/v3:"BLSIL"
|
||||
return x & -x
|
||||
}
|
||||
|
||||
func blsmsk64(x int64) int64 {
|
||||
// amd64/v3:"BLSMSKQ"
|
||||
return x ^ (x - 1)
|
||||
}
|
||||
|
||||
func blsmsk32(x int32) int32 {
|
||||
// amd64/v3:"BLSMSKL"
|
||||
return x ^ (x - 1)
|
||||
}
|
||||
|
||||
func blsr64(x int64) int64 {
|
||||
// amd64/v3:"BLSRQ"
|
||||
return x & (x - 1)
|
||||
}
|
||||
|
||||
func blsr32(x int32) int32 {
|
||||
// amd64/v3:"BLSRL"
|
||||
return x & (x - 1)
|
||||
}
|
||||
|
||||
func isPowerOfTwo64(x int64) bool {
|
||||
// amd64/v3:"BLSRQ" -"TESTQ" -"CALL"
|
||||
return blsr64(x) == 0
|
||||
}
|
||||
|
||||
func isPowerOfTwo32(x int32) bool {
|
||||
// amd64/v3:"BLSRL" -"TESTL" -"CALL"
|
||||
return blsr32(x) == 0
|
||||
}
|
||||
|
||||
func isPowerOfTwoSelect64(x, a, b int64) int64 {
|
||||
var r int64
|
||||
// amd64/v3:"BLSRQ" -"TESTQ" -"CALL"
|
||||
if isPowerOfTwo64(x) {
|
||||
r = a
|
||||
} else {
|
||||
r = b
|
||||
}
|
||||
// amd64/v3:"CMOVQEQ" -"TESTQ" -"CALL"
|
||||
return r * 2 // force return blocks joining
|
||||
}
|
||||
|
||||
func isPowerOfTwoSelect32(x, a, b int32) int32 {
|
||||
var r int32
|
||||
// amd64/v3:"BLSRL" -"TESTL" -"CALL"
|
||||
if isPowerOfTwo32(x) {
|
||||
r = a
|
||||
} else {
|
||||
r = b
|
||||
}
|
||||
// amd64/v3:"CMOVLEQ" -"TESTL" -"CALL"
|
||||
return r * 2 // force return blocks joining
|
||||
}
|
||||
|
||||
func isPowerOfTwoBranch64(x int64, a func(bool), b func(string)) {
|
||||
// amd64/v3:"BLSRQ" -"TESTQ" -"CALL"
|
||||
if isPowerOfTwo64(x) {
|
||||
a(true)
|
||||
} else {
|
||||
b("false")
|
||||
}
|
||||
}
|
||||
|
||||
func isPowerOfTwoBranch32(x int32, a func(bool), b func(string)) {
|
||||
// amd64/v3:"BLSRL" -"TESTL" -"CALL"
|
||||
if isPowerOfTwo32(x) {
|
||||
a(true)
|
||||
} else {
|
||||
b("false")
|
||||
}
|
||||
}
|
||||
|
||||
func isNotPowerOfTwo64(x int64) bool {
|
||||
// amd64/v3:"BLSRQ" -"TESTQ" -"CALL"
|
||||
return blsr64(x) != 0
|
||||
}
|
||||
|
||||
func isNotPowerOfTwo32(x int32) bool {
|
||||
// amd64/v3:"BLSRL" -"TESTL" -"CALL"
|
||||
return blsr32(x) != 0
|
||||
}
|
||||
|
||||
func isNotPowerOfTwoSelect64(x, a, b int64) int64 {
|
||||
var r int64
|
||||
// amd64/v3:"BLSRQ" -"TESTQ" -"CALL"
|
||||
if isNotPowerOfTwo64(x) {
|
||||
r = a
|
||||
} else {
|
||||
r = b
|
||||
}
|
||||
// amd64/v3:"CMOVQNE" -"TESTQ" -"CALL"
|
||||
return r * 2 // force return blocks joining
|
||||
}
|
||||
|
||||
func isNotPowerOfTwoSelect32(x, a, b int32) int32 {
|
||||
var r int32
|
||||
// amd64/v3:"BLSRL" -"TESTL" -"CALL"
|
||||
if isNotPowerOfTwo32(x) {
|
||||
r = a
|
||||
} else {
|
||||
r = b
|
||||
}
|
||||
// amd64/v3:"CMOVLNE" -"TESTL" -"CALL"
|
||||
return r * 2 // force return blocks joining
|
||||
}
|
||||
|
||||
func isNotPowerOfTwoBranch64(x int64, a func(bool), b func(string)) {
|
||||
// amd64/v3:"BLSRQ" -"TESTQ" -"CALL"
|
||||
if isNotPowerOfTwo64(x) {
|
||||
a(true)
|
||||
} else {
|
||||
b("false")
|
||||
}
|
||||
}
|
||||
|
||||
func isNotPowerOfTwoBranch32(x int32, a func(bool), b func(string)) {
|
||||
// amd64/v3:"BLSRL" -"TESTL" -"CALL"
|
||||
if isNotPowerOfTwo32(x) {
|
||||
a(true)
|
||||
} else {
|
||||
b("false")
|
||||
}
|
||||
}
|
||||
|
||||
func sarx64(x, y int64) int64 {
|
||||
// amd64/v3:"SARXQ"
|
||||
return x >> y
|
||||
}
|
||||
|
||||
func sarx32(x, y int32) int32 {
|
||||
// amd64/v3:"SARXL"
|
||||
return x >> y
|
||||
}
|
||||
|
||||
func sarx64_load(x []int64, i int) int64 {
|
||||
// amd64/v3: `SARXQ [A-Z]+[0-9]*, \([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s := x[i] >> (i & 63)
|
||||
// amd64/v3: `SARXQ [A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s = x[i+1] >> (s & 63)
|
||||
return s
|
||||
}
|
||||
|
||||
func sarx32_load(x []int32, i int) int32 {
|
||||
// amd64/v3: `SARXL [A-Z]+[0-9]*, \([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s := x[i] >> (i & 63)
|
||||
// amd64/v3: `SARXL [A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s = x[i+1] >> (s & 63)
|
||||
return s
|
||||
}
|
||||
|
||||
func shlrx64(x, y uint64) uint64 {
|
||||
// amd64/v3:"SHRXQ"
|
||||
s := x >> y
|
||||
// amd64/v3:"SHLXQ"
|
||||
s = s << y
|
||||
return s
|
||||
}
|
||||
|
||||
func shlrx32(x, y uint32) uint32 {
|
||||
// amd64/v3:"SHRXL"
|
||||
s := x >> y
|
||||
// amd64/v3:"SHLXL"
|
||||
s = s << y
|
||||
return s
|
||||
}
|
||||
|
||||
func shlrx64_load(x []uint64, i int, s uint64) uint64 {
|
||||
// amd64/v3: `SHRXQ [A-Z]+[0-9]*, \([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s = x[i] >> i
|
||||
// amd64/v3: `SHLXQ [A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s = x[i+1] << s
|
||||
return s
|
||||
}
|
||||
|
||||
func shlrx32_load(x []uint32, i int, s uint32) uint32 {
|
||||
// amd64/v3: `SHRXL [A-Z]+[0-9]*, \([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s = x[i] >> i
|
||||
// amd64/v3: `SHLXL [A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s = x[i+1] << s
|
||||
return s
|
||||
}
|
||||
330
test/codegen/bool.go
Normal file
330
test/codegen/bool.go
Normal file
@@ -0,0 +1,330 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2020 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 (
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// This file contains codegen tests related to boolean simplifications/optimizations.
|
||||
|
||||
func convertNeq0B(x uint8, c bool) bool {
|
||||
// amd64:"ANDL [$]1" -"SETNE"
|
||||
// ppc64x:"RLDICL" -"CMPW" -"ISEL"
|
||||
b := x&1 != 0
|
||||
return c && b
|
||||
}
|
||||
|
||||
func convertNeq0W(x uint16, c bool) bool {
|
||||
// amd64:"ANDL [$]1" -"SETNE"
|
||||
// ppc64x:"RLDICL" -"CMPW" -"ISEL"
|
||||
b := x&1 != 0
|
||||
return c && b
|
||||
}
|
||||
|
||||
func convertNeq0L(x uint32, c bool) bool {
|
||||
// amd64:"ANDL [$]1" -"SETB"
|
||||
// ppc64x:"RLDICL" -"CMPW" -"ISEL"
|
||||
b := x&1 != 0
|
||||
return c && b
|
||||
}
|
||||
|
||||
func convertNeq0Q(x uint64, c bool) bool {
|
||||
// amd64:"ANDL [$]1" -"SETB"
|
||||
// ppc64x:"RLDICL" -"CMP" -"ISEL"
|
||||
b := x&1 != 0
|
||||
return c && b
|
||||
}
|
||||
|
||||
func convertNeqBool32(x uint32) bool {
|
||||
// ppc64x:"RLDICL" -"CMPW" -"ISEL"
|
||||
return x&1 != 0
|
||||
}
|
||||
|
||||
func convertEqBool32(x uint32) bool {
|
||||
// ppc64x:"RLDICL" -"CMPW" "XOR" -"ISEL"
|
||||
// amd64:"ANDL" "XORL" -"BTL" -"SETCC"
|
||||
return x&1 == 0
|
||||
}
|
||||
|
||||
func convertNeqBool64(x uint64) bool {
|
||||
// ppc64x:"RLDICL" -"CMP" -"ISEL"
|
||||
return x&1 != 0
|
||||
}
|
||||
|
||||
func convertEqBool64(x uint64) bool {
|
||||
// ppc64x:"RLDICL" "XOR" -"CMP" -"ISEL"
|
||||
// amd64:"ANDL" "XORL" -"BTL" -"SETCC"
|
||||
return x&1 == 0
|
||||
}
|
||||
|
||||
func phiAnd(a, b bool) bool {
|
||||
var x bool
|
||||
// amd64:-"TESTB"
|
||||
if a {
|
||||
x = b
|
||||
} else {
|
||||
x = a
|
||||
}
|
||||
// amd64:"ANDL"
|
||||
return x
|
||||
}
|
||||
|
||||
func phiOr(a, b bool) bool {
|
||||
var x bool
|
||||
// amd64:-"TESTB"
|
||||
if a {
|
||||
x = a
|
||||
} else {
|
||||
x = b
|
||||
}
|
||||
// amd64:"ORL"
|
||||
return x
|
||||
}
|
||||
|
||||
func TestSetEq64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBC CR0EQ" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBC CR0EQ"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBC CR0EQ"
|
||||
b := x == y
|
||||
return b
|
||||
}
|
||||
func TestSetNeq64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0EQ" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBCR CR0EQ"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBCR CR0EQ"
|
||||
b := x != y
|
||||
return b
|
||||
}
|
||||
func TestSetLt64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBC CR0GT" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBC CR0GT"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBC CR0GT"
|
||||
b := x < y
|
||||
return b
|
||||
}
|
||||
func TestSetLe64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBCR CR0LT"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBCR CR0LT"
|
||||
b := x <= y
|
||||
return b
|
||||
}
|
||||
func TestSetGt64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBC CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBC CR0LT"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBC CR0LT"
|
||||
b := x > y
|
||||
return b
|
||||
}
|
||||
func TestSetGe64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0GT" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBCR CR0GT"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBCR CR0GT"
|
||||
b := x >= y
|
||||
return b
|
||||
}
|
||||
func TestSetLtFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBC CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"FCMP" "ISEL" -"SETBC CR0LT"
|
||||
// ppc64x/power8:"FCMP" "ISEL" -"SETBC CR0LT"
|
||||
b := x < y
|
||||
return b
|
||||
}
|
||||
func TestSetLeFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBC CR0LT" "SETBC CR0EQ" "OR" -"ISEL" -"ISEL"
|
||||
// ppc64x/power9:"ISEL" "ISEL" -"SETBC CR0LT" -"SETBC CR0EQ" "OR"
|
||||
// ppc64x/power8:"ISEL" "ISEL" -"SETBC CR0LT" -"SETBC CR0EQ" "OR"
|
||||
b := x <= y
|
||||
return b
|
||||
}
|
||||
func TestSetGtFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBC CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"FCMP" "ISEL" -"SETBC CR0LT"
|
||||
// ppc64x/power8:"FCMP" "ISEL" -"SETBC CR0LT"
|
||||
b := x > y
|
||||
return b
|
||||
}
|
||||
func TestSetGeFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBC CR0LT" "SETBC CR0EQ" "OR" -"ISEL" -"ISEL"
|
||||
// ppc64x/power9:"ISEL" "ISEL" -"SETBC CR0LT" -"SETBC CR0EQ" "OR"
|
||||
// ppc64x/power8:"ISEL" "ISEL" -"SETBC CR0LT" -"SETBC CR0EQ" "OR"
|
||||
b := x >= y
|
||||
return b
|
||||
}
|
||||
func TestSetInvEq64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0EQ" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBCR CR0EQ"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBCR CR0EQ"
|
||||
b := !(x == y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvNeq64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBC CR0EQ" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBC CR0EQ"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBC CR0EQ"
|
||||
b := !(x != y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvLt64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0GT" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBCR CR0GT"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBCR CR0GT"
|
||||
b := !(x < y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvLe64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBC CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBC CR0LT"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBC CR0LT"
|
||||
b := !(x <= y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvGt64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBCR CR0LT"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBCR CR0LT"
|
||||
b := !(x > y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvGe64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBC CR0GT" -"ISEL"
|
||||
// ppc64x/power9:"CMP" "ISEL" -"SETBC CR0GT"
|
||||
// ppc64x/power8:"CMP" "ISEL" -"SETBC CR0GT"
|
||||
b := !(x >= y)
|
||||
return b
|
||||
}
|
||||
|
||||
func TestSetInvEqFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0EQ" -"ISEL"
|
||||
// ppc64x/power9:"FCMP" "ISEL" -"SETBCR CR0EQ"
|
||||
// ppc64x/power8:"FCMP" "ISEL" -"SETBCR CR0EQ"
|
||||
b := !(x == y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvNeqFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBC CR0EQ" -"ISEL"
|
||||
// ppc64x/power9:"FCMP" "ISEL" -"SETBC CR0EQ"
|
||||
// ppc64x/power8:"FCMP" "ISEL" -"SETBC CR0EQ"
|
||||
b := !(x != y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvLtFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"FCMP" "ISEL" -"SETBCR CR0LT"
|
||||
// ppc64x/power8:"FCMP" "ISEL" -"SETBCR CR0LT"
|
||||
b := !(x < y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvLeFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBC CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"FCMP" "ISEL" -"SETBC CR0LT"
|
||||
// ppc64x/power8:"FCMP" "ISEL" -"SETBC CR0LT"
|
||||
b := !(x <= y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvGtFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBCR CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"FCMP" "ISEL" -"SETBCR CR0LT"
|
||||
// ppc64x/power8:"FCMP" "ISEL" -"SETBCR CR0LT"
|
||||
b := !(x > y)
|
||||
return b
|
||||
}
|
||||
func TestSetInvGeFp64(x float64, y float64) bool {
|
||||
// ppc64x/power10:"SETBC CR0LT" -"ISEL"
|
||||
// ppc64x/power9:"FCMP" "ISEL" -"SETBC CR0LT"
|
||||
// ppc64x/power8:"FCMP" "ISEL" -"SETBC CR0LT"
|
||||
b := !(x >= y)
|
||||
return b
|
||||
}
|
||||
func TestLogicalCompareZero(x *[64]uint64) {
|
||||
// ppc64x:"ANDCC",^"AND"
|
||||
b := x[0] & 3
|
||||
if b != 0 {
|
||||
x[0] = b
|
||||
}
|
||||
// ppc64x:"ANDCC",^"AND"
|
||||
b = x[1] & x[2]
|
||||
if b != 0 {
|
||||
x[1] = b
|
||||
}
|
||||
// ppc64x:"ANDNCC",^"ANDN"
|
||||
b = x[1] &^ x[2]
|
||||
if b != 0 {
|
||||
x[1] = b
|
||||
}
|
||||
// ppc64x:"ORCC",^"OR"
|
||||
b = x[3] | x[4]
|
||||
if b != 0 {
|
||||
x[3] = b
|
||||
}
|
||||
// ppc64x:"SUBCC",^"SUB"
|
||||
b = x[5] - x[6]
|
||||
if b != 0 {
|
||||
x[5] = b
|
||||
}
|
||||
// ppc64x:"NORCC",^"NOR"
|
||||
b = ^(x[5] | x[6])
|
||||
if b != 0 {
|
||||
x[5] = b
|
||||
}
|
||||
// ppc64x:"XORCC",^"XOR"
|
||||
b = x[7] ^ x[8]
|
||||
if b != 0 {
|
||||
x[7] = b
|
||||
}
|
||||
// ppc64x:"ADDCC",^"ADD"
|
||||
b = x[9] + x[10]
|
||||
if b != 0 {
|
||||
x[9] = b
|
||||
}
|
||||
// ppc64x:"NEGCC",^"NEG"
|
||||
b = -x[11]
|
||||
if b != 0 {
|
||||
x[11] = b
|
||||
}
|
||||
// ppc64x:"CNTLZDCC",^"CNTLZD"
|
||||
b = uint64(bits.LeadingZeros64(x[12]))
|
||||
if b != 0 {
|
||||
x[12] = b
|
||||
}
|
||||
|
||||
// ppc64x:"ADDCCC [$]4,"
|
||||
c := int64(x[12]) + 4
|
||||
if c <= 0 {
|
||||
x[12] = uint64(c)
|
||||
}
|
||||
|
||||
// ppc64x:"MULHDUCC",^"MULHDU"
|
||||
hi, _ := bits.Mul64(x[13], x[14])
|
||||
if hi != 0 {
|
||||
x[14] = hi
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func constantWrite(b bool, p *bool) {
|
||||
if b {
|
||||
// amd64:`MOVB [$]1, \(`
|
||||
*p = b
|
||||
}
|
||||
}
|
||||
|
||||
func boolCompare1(p, q *bool) int {
|
||||
// arm64:-"EOR [$]1"
|
||||
if *p == *q {
|
||||
return 5
|
||||
}
|
||||
return 7
|
||||
}
|
||||
func boolCompare2(p, q *bool) int {
|
||||
// arm64:-"EOR [$]1"
|
||||
if *p != *q {
|
||||
return 5
|
||||
}
|
||||
return 7
|
||||
}
|
||||
35
test/codegen/clobberdead.go
Normal file
35
test/codegen/clobberdead.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// asmcheck -gcflags=-clobberdead
|
||||
|
||||
//go:build amd64 || arm64
|
||||
|
||||
// Copyright 2021 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
|
||||
|
||||
type T [2]*int // contain pointer, not SSA-able (so locals are not registerized)
|
||||
|
||||
var p1, p2, p3 T
|
||||
|
||||
func F() {
|
||||
// 3735936685 is 0xdeaddead. On ARM64 R27 is REGTMP.
|
||||
// clobber x, y at entry. not clobber z (stack object).
|
||||
// amd64:`MOVL \$3735936685, command-line-arguments\.x`, `MOVL \$3735936685, command-line-arguments\.y`, -`MOVL \$3735936685, command-line-arguments\.z`
|
||||
// arm64:`MOVW R27, command-line-arguments\.x`, `MOVW R27, command-line-arguments\.y`, -`MOVW R27, command-line-arguments\.z`
|
||||
x, y, z := p1, p2, p3
|
||||
addrTaken(&z)
|
||||
// x is dead at the call (the value of x is loaded before the CALL), y is not
|
||||
// amd64:`MOVL \$3735936685, command-line-arguments\.x`, -`MOVL \$3735936685, command-line-arguments\.y`
|
||||
// arm64:`MOVW R27, command-line-arguments\.x`, -`MOVW R27, command-line-arguments\.y`
|
||||
use(x)
|
||||
// amd64:`MOVL \$3735936685, command-line-arguments\.x`, `MOVL \$3735936685, command-line-arguments\.y`
|
||||
// arm64:`MOVW R27, command-line-arguments\.x`, `MOVW R27, command-line-arguments\.y`
|
||||
use(y)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func use(T) {}
|
||||
|
||||
//go:noinline
|
||||
func addrTaken(*T) {}
|
||||
33
test/codegen/clobberdeadreg.go
Normal file
33
test/codegen/clobberdeadreg.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// asmcheck -gcflags=-clobberdeadreg
|
||||
|
||||
//go:build amd64
|
||||
|
||||
// Copyright 2021 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
|
||||
|
||||
type S struct {
|
||||
a, b, c, d, e, f int
|
||||
}
|
||||
|
||||
func F(a, b, c int, d S) {
|
||||
// -2401018187971961171 is 0xdeaddeaddeaddead
|
||||
// amd64:`MOVQ \$-2401018187971961171, AX`, `MOVQ \$-2401018187971961171, BX`, `MOVQ \$-2401018187971961171, CX`
|
||||
// amd64:`MOVQ \$-2401018187971961171, DX`, `MOVQ \$-2401018187971961171, SI`, `MOVQ \$-2401018187971961171, DI`
|
||||
// amd64:`MOVQ \$-2401018187971961171, R8`, `MOVQ \$-2401018187971961171, R9`, `MOVQ \$-2401018187971961171, R10`
|
||||
// amd64:`MOVQ \$-2401018187971961171, R11`, `MOVQ \$-2401018187971961171, R12`, `MOVQ \$-2401018187971961171, R13`
|
||||
// amd64:-`MOVQ \$-2401018187971961171, BP` // frame pointer is not clobbered
|
||||
StackArgsCall([10]int{a, b, c})
|
||||
// amd64:`MOVQ \$-2401018187971961171, R12`, `MOVQ \$-2401018187971961171, R13`, `MOVQ \$-2401018187971961171, DX`
|
||||
// amd64:-`MOVQ \$-2401018187971961171, AX`, -`MOVQ \$-2401018187971961171, R11` // register args are not clobbered
|
||||
RegArgsCall(a, b, c, d)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func StackArgsCall([10]int) {}
|
||||
|
||||
//go:noinline
|
||||
//go:registerparams
|
||||
func RegArgsCall(int, int, int, S) {}
|
||||
254
test/codegen/compare_and_branch.go
Normal file
254
test/codegen/compare_and_branch.go
Normal file
@@ -0,0 +1,254 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2019 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
|
||||
|
||||
//go:noinline
|
||||
func dummy() {}
|
||||
|
||||
// Signed 64-bit compare-and-branch.
|
||||
func si64(x, y chan int64) {
|
||||
// s390x:"CGRJ [$](2|4), R[0-9]+, R[0-9]+, "
|
||||
for <-x < <-y {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CL?GRJ [$]8, R[0-9]+, R[0-9]+, "
|
||||
for <-x == <-y {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Signed 64-bit compare-and-branch with 8-bit immediate.
|
||||
func si64x8(doNotOptimize int64) {
|
||||
// take in doNotOptimize as an argument to avoid the loops being rewritten to count down
|
||||
// s390x:"CGIJ [$]12, R[0-9]+, [$]127, "
|
||||
for i := doNotOptimize; i < 128; i++ {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CGIJ [$]10, R[0-9]+, [$]-128, "
|
||||
for i := doNotOptimize; i > -129; i-- {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CGIJ [$]2, R[0-9]+, [$]127, "
|
||||
for i := doNotOptimize; i >= 128; i++ {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CGIJ [$]4, R[0-9]+, [$]-128, "
|
||||
for i := doNotOptimize; i <= -129; i-- {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Unsigned 64-bit compare-and-branch.
|
||||
func ui64(x, y chan uint64) {
|
||||
// s390x:"CLGRJ [$](2|4), R[0-9]+, R[0-9]+, "
|
||||
for <-x > <-y {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CL?GRJ [$]6, R[0-9]+, R[0-9]+, "
|
||||
for <-x != <-y {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Unsigned 64-bit comparison with 8-bit immediate.
|
||||
func ui64x8() {
|
||||
// s390x:"CLGIJ [$]4, R[0-9]+, [$]128, "
|
||||
for i := uint64(0); i < 128; i++ {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CLGIJ [$]12, R[0-9]+, [$]255, "
|
||||
for i := uint64(0); i < 256; i++ {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CLGIJ [$]2, R[0-9]+, [$]255, "
|
||||
for i := uint64(257); i >= 256; i-- {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CLGIJ [$]2, R[0-9]+, [$]0, "
|
||||
for i := uint64(1024); i > 0; i-- {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Signed 32-bit compare-and-branch.
|
||||
func si32(x, y chan int32) {
|
||||
// s390x:"CRJ [$](2|4), R[0-9]+, R[0-9]+, "
|
||||
for <-x < <-y {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CL?RJ [$]8, R[0-9]+, R[0-9]+, "
|
||||
for <-x == <-y {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Signed 32-bit compare-and-branch with 8-bit immediate.
|
||||
func si32x8(doNotOptimize int32) {
|
||||
// take in doNotOptimize as an argument to avoid the loops being rewritten to count down
|
||||
// s390x:"CIJ [$]12, R[0-9]+, [$]127, "
|
||||
for i := doNotOptimize; i < 128; i++ {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CIJ [$]10, R[0-9]+, [$]-128, "
|
||||
for i := doNotOptimize; i > -129; i-- {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CIJ [$]2, R[0-9]+, [$]127, "
|
||||
for i := doNotOptimize; i >= 128; i++ {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CIJ [$]4, R[0-9]+, [$]-128, "
|
||||
for i := doNotOptimize; i <= -129; i-- {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Unsigned 32-bit compare-and-branch.
|
||||
func ui32(x, y chan uint32) {
|
||||
// s390x:"CLRJ [$](2|4), R[0-9]+, R[0-9]+, "
|
||||
for <-x > <-y {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CL?RJ [$]6, R[0-9]+, R[0-9]+, "
|
||||
for <-x != <-y {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Unsigned 32-bit comparison with 8-bit immediate.
|
||||
func ui32x8() {
|
||||
// s390x:"CLIJ [$]4, R[0-9]+, [$]128, "
|
||||
for i := uint32(0); i < 128; i++ {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CLIJ [$]12, R[0-9]+, [$]255, "
|
||||
for i := uint32(0); i < 256; i++ {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CLIJ [$]2, R[0-9]+, [$]255, "
|
||||
for i := uint32(257); i >= 256; i-- {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CLIJ [$]2, R[0-9]+, [$]0, "
|
||||
for i := uint32(1024); i > 0; i-- {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Signed 64-bit comparison with unsigned 8-bit immediate.
|
||||
func si64xu8(x chan int64) {
|
||||
// s390x:"CLGIJ [$]8, R[0-9]+, [$]128, "
|
||||
for <-x == 128 {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CLGIJ [$]6, R[0-9]+, [$]255, "
|
||||
for <-x != 255 {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Signed 32-bit comparison with unsigned 8-bit immediate.
|
||||
func si32xu8(x chan int32) {
|
||||
// s390x:"CLIJ [$]8, R[0-9]+, [$]255, "
|
||||
for <-x == 255 {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CLIJ [$]6, R[0-9]+, [$]128, "
|
||||
for <-x != 128 {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Unsigned 64-bit comparison with signed 8-bit immediate.
|
||||
func ui64xu8(x chan uint64) {
|
||||
// s390x:"CGIJ [$]8, R[0-9]+, [$]-1, "
|
||||
for <-x == ^uint64(0) {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CGIJ [$]6, R[0-9]+, [$]-128, "
|
||||
for <-x != ^uint64(127) {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Unsigned 32-bit comparison with signed 8-bit immediate.
|
||||
func ui32xu8(x chan uint32) {
|
||||
// s390x:"CIJ [$]8, R[0-9]+, [$]-128, "
|
||||
for <-x == ^uint32(127) {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// s390x:"CIJ [$]6, R[0-9]+, [$]-1, "
|
||||
for <-x != ^uint32(0) {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Signed 64-bit comparison with 1/-1 to comparison with 0.
|
||||
func si64x0(x chan int64) {
|
||||
// riscv64:"BGTZ"
|
||||
for <-x >= 1 {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// riscv64:"BLEZ"
|
||||
for <-x < 1 {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// riscv64:"BLTZ"
|
||||
for <-x <= -1 {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// riscv64:"BGEZ"
|
||||
for <-x > -1 {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
// Unsigned 64-bit comparison with 1 to comparison with 0.
|
||||
func ui64x0(x chan uint64) {
|
||||
// riscv64:"BNEZ"
|
||||
for <-x >= 1 {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// riscv64:"BEQZ"
|
||||
for <-x < 1 {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// riscv64:"BNEZ"
|
||||
for 0 < <-x {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// riscv64:"BEQZ"
|
||||
for 0 >= <-x {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
886
test/codegen/comparisons.go
Normal file
886
test/codegen/comparisons.go
Normal file
@@ -0,0 +1,886 @@
|
||||
// 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 (
|
||||
"cmp"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// This file contains code generation tests related to the comparison
|
||||
// operators.
|
||||
|
||||
// -------------- //
|
||||
// Equality //
|
||||
// -------------- //
|
||||
|
||||
// Check that compare to constant string use 2/4/8 byte compares
|
||||
|
||||
func CompareString1(s string) bool {
|
||||
// amd64:`CMPW \(.*\), [$]`
|
||||
// arm64:`MOVHU \(.*\), [R]`,`MOVD [$]`,`CMPW R`
|
||||
// ppc64le:`MOVHZ \(.*\), [R]`,`CMPW .*, [$]`
|
||||
// s390x:`MOVHBR \(.*\), [R]`,`CMPW .*, [$]`
|
||||
return s == "xx"
|
||||
}
|
||||
|
||||
func CompareString2(s string) bool {
|
||||
// amd64:`CMPL \(.*\), [$]`
|
||||
// arm64:`MOVWU \(.*\), [R]`,`CMPW .*, [R]`
|
||||
// ppc64le:`MOVWZ \(.*\), [R]`,`CMPW .*, [R]`
|
||||
// s390x:`MOVWBR \(.*\), [R]`,`CMPW .*, [$]`
|
||||
return s == "xxxx"
|
||||
}
|
||||
|
||||
func CompareString3(s string) bool {
|
||||
// amd64:`CMPQ \(.*\), [A-Z]`
|
||||
// arm64:-`CMPW `
|
||||
// ppc64x:-`CMPW `
|
||||
// s390x:-`CMPW `
|
||||
return s == "xxxxxxxx"
|
||||
}
|
||||
|
||||
// Check that arrays compare use 2/4/8 byte compares
|
||||
|
||||
func CompareArray1(a, b [2]byte) bool {
|
||||
// amd64:`CMPW command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
// arm64:-`MOVBU `
|
||||
// ppc64le:-`MOVBZ `
|
||||
// s390x:-`MOVBZ `
|
||||
return a == b
|
||||
}
|
||||
|
||||
func CompareArray2(a, b [3]uint16) bool {
|
||||
// amd64:`CMPL command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
// amd64:`CMPW command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
return a == b
|
||||
}
|
||||
|
||||
func CompareArray3(a, b [3]int16) bool {
|
||||
// amd64:`CMPL command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
// amd64:`CMPW command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
return a == b
|
||||
}
|
||||
|
||||
func CompareArray4(a, b [12]int8) bool {
|
||||
// amd64:`CMPQ command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
// amd64:`CMPL command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
return a == b
|
||||
}
|
||||
|
||||
func CompareArray5(a, b [15]byte) bool {
|
||||
// amd64:`CMPQ command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
return a == b
|
||||
}
|
||||
|
||||
// This was a TODO in mapaccess1_faststr
|
||||
func CompareArray6(a, b unsafe.Pointer) bool {
|
||||
// amd64:`CMPL \(.*\), [A-Z]`
|
||||
// arm64:`MOVWU \(.*\), [R]`,`CMPW .*, [R]`
|
||||
// ppc64le:`MOVWZ \(.*\), [R]`,`CMPW .*, [R]`
|
||||
// s390x:`MOVWBR \(.*\), [R]`,`CMPW .*, [R]`
|
||||
return *((*[4]byte)(a)) != *((*[4]byte)(b))
|
||||
}
|
||||
|
||||
// Check that some structs generate 2/4/8 byte compares.
|
||||
|
||||
type T1 struct {
|
||||
a [8]byte
|
||||
}
|
||||
|
||||
func CompareStruct1(s1, s2 T1) bool {
|
||||
// amd64:`CMPQ command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
// amd64:-`CALL`
|
||||
return s1 == s2
|
||||
}
|
||||
|
||||
type T2 struct {
|
||||
a [16]byte
|
||||
}
|
||||
|
||||
func CompareStruct2(s1, s2 T2) bool {
|
||||
// amd64:`CMPQ command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
// amd64:-`CALL`
|
||||
return s1 == s2
|
||||
}
|
||||
|
||||
// Assert that a memequal call is still generated when
|
||||
// inlining would increase binary size too much.
|
||||
|
||||
type T3 struct {
|
||||
a [24]byte
|
||||
}
|
||||
|
||||
func CompareStruct3(s1, s2 T3) bool {
|
||||
// amd64:-`CMPQ command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
// amd64:`CALL`
|
||||
return s1 == s2
|
||||
}
|
||||
|
||||
type T4 struct {
|
||||
a [32]byte
|
||||
}
|
||||
|
||||
func CompareStruct4(s1, s2 T4) bool {
|
||||
// amd64:-`CMPQ command-line-arguments[.+_a-z0-9]+\(SP\), [A-Z]`
|
||||
// amd64:`CALL`
|
||||
return s1 == s2
|
||||
}
|
||||
|
||||
// -------------- //
|
||||
// Ordering //
|
||||
// -------------- //
|
||||
|
||||
// Test that LEAQ/ADDQconst are folded into SETx ops
|
||||
|
||||
var r bool
|
||||
|
||||
func CmpFold(x uint32) {
|
||||
// amd64:`SETHI .*\(SB\)`
|
||||
r = x > 4
|
||||
}
|
||||
|
||||
// Test that direct comparisons with memory are generated when
|
||||
// possible
|
||||
|
||||
func CmpMem1(p int, q *int) bool {
|
||||
// amd64:`CMPQ \(.*\), [A-Z]`
|
||||
return p < *q
|
||||
}
|
||||
|
||||
func CmpMem2(p *int, q int) bool {
|
||||
// amd64:`CMPQ \(.*\), [A-Z]`
|
||||
return *p < q
|
||||
}
|
||||
|
||||
func CmpMem3(p *int) bool {
|
||||
// amd64:`CMPQ \(.*\), [$]7`
|
||||
return *p < 7
|
||||
}
|
||||
|
||||
func CmpMem4(p *int) bool {
|
||||
// amd64:`CMPQ \(.*\), [$]7`
|
||||
return 7 < *p
|
||||
}
|
||||
|
||||
func CmpMem5(p **int) {
|
||||
// amd64:`CMPL runtime.writeBarrier\(SB\), [$]0`
|
||||
*p = nil
|
||||
}
|
||||
|
||||
func CmpMem6(a []int) int {
|
||||
// 386:`CMPL\s8\([A-Z]+\),`
|
||||
// amd64:`CMPQ\s16\([A-Z]+\),`
|
||||
if a[1] > a[2] {
|
||||
return 1
|
||||
} else {
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
// Check tbz/tbnz are generated when comparing against zero on arm64
|
||||
|
||||
func CmpZero1(a int32, ptr *int) {
|
||||
if a < 0 { // arm64:"TBZ"
|
||||
*ptr = 0
|
||||
}
|
||||
}
|
||||
|
||||
func CmpZero2(a int64, ptr *int) {
|
||||
if a < 0 { // arm64:"TBZ"
|
||||
*ptr = 0
|
||||
}
|
||||
}
|
||||
|
||||
func CmpZero3(a int32, ptr *int) {
|
||||
if a >= 0 { // arm64:"TBNZ"
|
||||
*ptr = 0
|
||||
}
|
||||
}
|
||||
|
||||
func CmpZero4(a int64, ptr *int) {
|
||||
if a >= 0 { // arm64:"TBNZ"
|
||||
*ptr = 0
|
||||
}
|
||||
}
|
||||
|
||||
func CmpToZero(a, b, d int32, e, f int64, deOptC0, deOptC1 bool) int32 {
|
||||
// arm:`TST`,-`AND`
|
||||
// arm64:`TSTW`,-`AND`
|
||||
// 386:`TESTL`,-`ANDL`
|
||||
// amd64:`TESTL`,-`ANDL`
|
||||
c0 := a&b < 0
|
||||
// arm:`CMN`,-`ADD`
|
||||
// arm64:`CMNW`,-`ADD`
|
||||
c1 := a+b < 0
|
||||
// arm:`TEQ`,-`XOR`
|
||||
c2 := a^b < 0
|
||||
// arm64:`TST`,-`AND`
|
||||
// amd64:`TESTQ`,-`ANDQ`
|
||||
c3 := e&f < 0
|
||||
// arm64:`CMN`,-`ADD`
|
||||
c4 := e+f < 0
|
||||
// not optimized to single CMNW/CMN due to further use of b+d
|
||||
// arm64:`ADD`,-`CMNW`
|
||||
// arm:`ADD`,-`CMN`
|
||||
c5 := b+d == 0
|
||||
// not optimized to single TSTW/TST due to further use of a&d
|
||||
// arm64:`AND`,-`TSTW`
|
||||
// arm:`AND`,-`TST`
|
||||
// 386:`ANDL`
|
||||
c6 := a&d >= 0
|
||||
// For arm64, could be TST+BGE or AND+TBZ
|
||||
c7 := e&(f<<3) < 0
|
||||
// For arm64, could be CMN+BPL or ADD+TBZ
|
||||
c8 := e+(f<<3) < 0
|
||||
// arm64:`TST\sR[0-9],\sR[0-9]+`
|
||||
c9 := e&(-19) < 0
|
||||
if c0 {
|
||||
return 1
|
||||
} else if c1 {
|
||||
return 2
|
||||
} else if c2 {
|
||||
return 3
|
||||
} else if c3 {
|
||||
return 4
|
||||
} else if c4 {
|
||||
return 5
|
||||
} else if c5 {
|
||||
return 6
|
||||
} else if c6 {
|
||||
return 7
|
||||
} else if c7 {
|
||||
return 9
|
||||
} else if c8 {
|
||||
return 10
|
||||
} else if c9 {
|
||||
return 11
|
||||
} else if deOptC0 {
|
||||
return b + d
|
||||
} else if deOptC1 {
|
||||
return a & d
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func CmpLogicalToZero(a, b, c uint32, d, e, f, g uint64) uint64 {
|
||||
|
||||
// ppc64x:"ANDCC" -"CMPW"
|
||||
// wasm:"I64Eqz" -"I32Eqz" -"I64ExtendI32U" -"I32WrapI64"
|
||||
if a&63 == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// ppc64x:"ANDCC" -"CMP"
|
||||
// wasm:"I64Eqz" -"I32Eqz" -"I64ExtendI32U" -"I32WrapI64"
|
||||
if d&255 == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// ppc64x:"ANDCC" -"CMP"
|
||||
// wasm:"I64Eqz" -"I32Eqz" -"I64ExtendI32U" -"I32WrapI64"
|
||||
if d&e == 0 {
|
||||
return 1
|
||||
}
|
||||
// ppc64x:"ORCC" -"CMP"
|
||||
// wasm:"I64Eqz" -"I32Eqz" -"I64ExtendI32U" -"I32WrapI64"
|
||||
if f|g == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// ppc64x:"XORCC" -"CMP"
|
||||
// wasm:"I64Eqz" "I32Eqz" -"I64ExtendI32U" -"I32WrapI64"
|
||||
if e^d == 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// The following CmpToZero_ex* check that cmp|cmn with bmi|bpl are generated for
|
||||
// 'comparing to zero' expressions
|
||||
|
||||
// var + const
|
||||
// 'x-const' might be canonicalized to 'x+(-const)', so we check both
|
||||
// CMN and CMP for subtraction expressions to make the pattern robust.
|
||||
func CmpToZero_ex1(a int64, e int32) int {
|
||||
// arm64:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if a+3 < 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arm64:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)`
|
||||
if a+5 <= 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arm64:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if a+13 >= 0 {
|
||||
return 2
|
||||
}
|
||||
|
||||
// arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)`
|
||||
if a-7 < 0 {
|
||||
return 3
|
||||
}
|
||||
|
||||
// arm64:`SUB`,`TBZ`
|
||||
if a-11 >= 0 {
|
||||
return 4
|
||||
}
|
||||
|
||||
// arm64:`SUB`,`CMP`,`BGT`
|
||||
if a-19 > 0 {
|
||||
return 4
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if e+3 < 0 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if e+13 >= 0 {
|
||||
return 6
|
||||
}
|
||||
|
||||
// arm64:`CMPW|CMNW`,`(BMI|BPL)`
|
||||
// arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)`
|
||||
if e-7 < 0 {
|
||||
return 7
|
||||
}
|
||||
|
||||
// arm64:`SUB`,`TBNZ`
|
||||
// arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)`
|
||||
if e-11 >= 0 {
|
||||
return 8
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// var + var
|
||||
// TODO: optimize 'var - var'
|
||||
func CmpToZero_ex2(a, b, c int64, e, f, g int32) int {
|
||||
// arm64:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if a+b < 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arm64:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)`
|
||||
if a+c <= 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arm64:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if b+c >= 0 {
|
||||
return 2
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if e+f < 0 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||
if f+g >= 0 {
|
||||
return 6
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// var + var*var
|
||||
func CmpToZero_ex3(a, b, c, d int64, e, f, g, h int32) int {
|
||||
// arm64:`CMN`,-`MADD`,`MUL`,`(BMI|BPL)`
|
||||
if a+b*c < 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arm64:`CMN`,-`MADD`,`MUL`,`(BMI|BPL)`
|
||||
if b+c*d >= 0 {
|
||||
return 2
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)`
|
||||
if e+f*g > 0 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
|
||||
// arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)`
|
||||
if f+g*h <= 0 {
|
||||
return 6
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// var - var*var
|
||||
func CmpToZero_ex4(a, b, c, d int64, e, f, g, h int32) int {
|
||||
// arm64:`CMP`,-`MSUB`,`MUL`,`BEQ`,`(BMI|BPL)`
|
||||
if a-b*c > 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arm64:`CMP`,-`MSUB`,`MUL`,`(BMI|BPL)`
|
||||
if b-c*d >= 0 {
|
||||
return 2
|
||||
}
|
||||
|
||||
// arm64:`CMPW`,-`MSUBW`,`MULW`,`(BMI|BPL)`
|
||||
if e-f*g < 0 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// arm64:`CMPW`,-`MSUBW`,`MULW`,`(BMI|BPL)`
|
||||
if f-g*h >= 0 {
|
||||
return 6
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func CmpToZero_ex5(e, f int32, u uint32) int {
|
||||
// arm:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)`
|
||||
if e+f<<1 > 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// arm:`CMP`,-`SUB`,`(BMI|BPL)`
|
||||
if f-int32(u>>2) >= 0 {
|
||||
return 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func UintLtZero(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// amd64: -`(TESTB|TESTW|TESTL|TESTQ|JCC|JCS)`
|
||||
// arm64: -`(CMPW|CMP|BHS|BLO)`
|
||||
if a < 0 || b < 0 || c < 0 || d < 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func UintGeqZero(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// amd64: -`(TESTB|TESTW|TESTL|TESTQ|JCS|JCC)`
|
||||
// arm64: -`(CMPW|CMP|BLO|BHS)`
|
||||
if a >= 0 || b >= 0 || c >= 0 || d >= 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func UintGtZero(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// arm64: `(CBN?ZW)`, `(CBN?Z[^W])`, -`(CMPW|CMP|BLS|BHI)`
|
||||
if a > 0 || b > 0 || c > 0 || d > 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func UintLeqZero(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// arm64: `(CBN?ZW)`, `(CBN?Z[^W])`, -`(CMPW|CMP|BHI|BLS)`
|
||||
if a <= 0 || b <= 0 || c <= 0 || d <= 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func UintLtOne(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// arm64: `(CBN?ZW)`, `(CBN?Z[^W])`, -`(CMPW|CMP|BHS|BLO)`
|
||||
if a < 1 || b < 1 || c < 1 || d < 1 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func UintGeqOne(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// arm64: `(CBN?ZW)`, `(CBN?Z[^W])`, -`(CMPW|CMP|BLO|BHS)`
|
||||
if a >= 1 || b >= 1 || c >= 1 || d >= 1 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func CmpToZeroU_ex1(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// wasm:"I64Eqz"-"I64LtU"
|
||||
if 0 < a {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LtU"
|
||||
if 0 < b {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LtU"
|
||||
if 0 < c {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LtU"
|
||||
if 0 < d {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func CmpToZeroU_ex2(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// wasm:"I64Eqz"-"I64LeU"
|
||||
if a <= 0 {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LeU"
|
||||
if b <= 0 {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LeU"
|
||||
if c <= 0 {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LeU"
|
||||
if d <= 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func CmpToOneU_ex1(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// wasm:"I64Eqz"-"I64LtU"
|
||||
if a < 1 {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LtU"
|
||||
if b < 1 {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LtU"
|
||||
if c < 1 {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LtU"
|
||||
if d < 1 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func CmpToOneU_ex2(a uint8, b uint16, c uint32, d uint64) int {
|
||||
// wasm:"I64Eqz"-"I64LeU"
|
||||
if 1 <= a {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LeU"
|
||||
if 1 <= b {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LeU"
|
||||
if 1 <= c {
|
||||
return 1
|
||||
}
|
||||
// wasm:"I64Eqz"-"I64LeU"
|
||||
if 1 <= d {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Check that small memequals are replaced with eq instructions
|
||||
|
||||
func equalConstString1() bool {
|
||||
a := string("A")
|
||||
b := string("Z")
|
||||
// amd64:-".*memequal"
|
||||
// arm64:-".*memequal"
|
||||
// ppc64x:-".*memequal"
|
||||
return a == b
|
||||
}
|
||||
|
||||
func equalVarString1(a string) bool {
|
||||
b := string("Z")
|
||||
// amd64:-".*memequal"
|
||||
// arm64:-".*memequal"
|
||||
// ppc64x:-".*memequal"
|
||||
return a[:1] == b
|
||||
}
|
||||
|
||||
func equalConstString2() bool {
|
||||
a := string("AA")
|
||||
b := string("ZZ")
|
||||
// amd64:-".*memequal"
|
||||
// arm64:-".*memequal"
|
||||
// ppc64x:-".*memequal"
|
||||
return a == b
|
||||
}
|
||||
|
||||
func equalVarString2(a string) bool {
|
||||
b := string("ZZ")
|
||||
// amd64:-".*memequal"
|
||||
// arm64:-".*memequal"
|
||||
// ppc64x:-".*memequal"
|
||||
return a[:2] == b
|
||||
}
|
||||
|
||||
func equalConstString4() bool {
|
||||
a := string("AAAA")
|
||||
b := string("ZZZZ")
|
||||
// amd64:-".*memequal"
|
||||
// arm64:-".*memequal"
|
||||
// ppc64x:-".*memequal"
|
||||
return a == b
|
||||
}
|
||||
|
||||
func equalVarString4(a string) bool {
|
||||
b := string("ZZZZ")
|
||||
// amd64:-".*memequal"
|
||||
// arm64:-".*memequal"
|
||||
// ppc64x:-".*memequal"
|
||||
return a[:4] == b
|
||||
}
|
||||
|
||||
func equalConstString8() bool {
|
||||
a := string("AAAAAAAA")
|
||||
b := string("ZZZZZZZZ")
|
||||
// amd64:-".*memequal"
|
||||
// arm64:-".*memequal"
|
||||
// ppc64x:-".*memequal"
|
||||
return a == b
|
||||
}
|
||||
|
||||
func equalVarString8(a string) bool {
|
||||
b := string("ZZZZZZZZ")
|
||||
// amd64:-".*memequal"
|
||||
// arm64:-".*memequal"
|
||||
// ppc64x:-".*memequal"
|
||||
return a[:8] == b
|
||||
}
|
||||
|
||||
func equalVarStringNoSpill(a, b string) bool {
|
||||
s := string("ZZZZZZZZZ")
|
||||
// arm64:".*memequal"
|
||||
memeq1 := a[:9] == s
|
||||
// arm64:-".*"
|
||||
memeq2 := s == a[:9]
|
||||
// arm64:-"MOVB R0,.*SP",".*memequal"
|
||||
memeq3 := s == b[:9]
|
||||
return memeq1 && memeq2 && memeq3
|
||||
}
|
||||
|
||||
func cmpToCmn(a, b, c, d int) int {
|
||||
var c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 int
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if a < -8 {
|
||||
c1 = 1
|
||||
}
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if a+1 == 0 {
|
||||
c2 = 1
|
||||
}
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if a+3 != 0 {
|
||||
c3 = 1
|
||||
}
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if a+b == 0 {
|
||||
c4 = 1
|
||||
}
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if b+c != 0 {
|
||||
c5 = 1
|
||||
}
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if a == -c {
|
||||
c6 = 1
|
||||
}
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if b != -d {
|
||||
c7 = 1
|
||||
}
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if a*b+c == 0 {
|
||||
c8 = 1
|
||||
}
|
||||
// arm64:`CMN`,-`CMP`
|
||||
if a*c+b != 0 {
|
||||
c9 = 1
|
||||
}
|
||||
// arm64:`CMP`,-`CMN`
|
||||
if b*c-a == 0 {
|
||||
c10 = 1
|
||||
}
|
||||
// arm64:`CMP`,-`CMN`
|
||||
if a*d-b != 0 {
|
||||
c11 = 1
|
||||
}
|
||||
return c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + c11
|
||||
}
|
||||
|
||||
func cmpToCmnLessThan(a, b, c, d int) int {
|
||||
var c1, c2, c3, c4 int
|
||||
// arm64:`CMN`,`CSET MI`,-`CMP`
|
||||
if a+1 < 0 {
|
||||
c1 = 1
|
||||
}
|
||||
// arm64:`CMN`,`CSET MI`,-`CMP`
|
||||
if a+b < 0 {
|
||||
c2 = 1
|
||||
}
|
||||
// arm64:`CMN`,`CSET MI`,-`CMP`
|
||||
if a*b+c < 0 {
|
||||
c3 = 1
|
||||
}
|
||||
// arm64:`CMP`,`CSET MI`,-`CMN`
|
||||
if a-b*c < 0 {
|
||||
c4 = 1
|
||||
}
|
||||
return c1 + c2 + c3 + c4
|
||||
}
|
||||
|
||||
func less128Signed32(x int32) bool {
|
||||
// amd64:`CMPL.*127`
|
||||
// amd64:`SETLE`
|
||||
return x < 128
|
||||
}
|
||||
|
||||
func less128Signed64(x int64) bool {
|
||||
// amd64:`CMPQ.*127`
|
||||
// amd64:`SETLE`
|
||||
return x < 128
|
||||
}
|
||||
|
||||
func less128Unsigned32(x uint32) bool {
|
||||
// amd64:`CMPL.*127`
|
||||
// amd64:`SETLS`
|
||||
return x < 128
|
||||
}
|
||||
|
||||
func less128Unsigned64(x uint64) bool {
|
||||
// amd64:`CMPQ.*127`
|
||||
// amd64:`SETLS`
|
||||
return x < 128
|
||||
}
|
||||
|
||||
func ge128Unsigned32(x uint32) bool {
|
||||
// amd64:`CMPL.*127`
|
||||
// amd64:`SETHI`
|
||||
return x >= 128
|
||||
}
|
||||
|
||||
func ge128Unsigned64(x uint64) bool {
|
||||
// amd64:`CMPQ.*127`
|
||||
// amd64:`SETHI`
|
||||
return x >= 128
|
||||
}
|
||||
|
||||
func ge128Signed32(x int32) bool {
|
||||
// amd64:`CMPL.*127`
|
||||
// amd64:`SETGT`
|
||||
return x >= 128
|
||||
}
|
||||
|
||||
func ge128Signed64(x int64) bool {
|
||||
// amd64:`CMPQ.*127`
|
||||
// amd64:`SETGT`
|
||||
return x >= 128
|
||||
}
|
||||
|
||||
func cmpToCmnGreaterThanEqual(a, b, c, d int) int {
|
||||
var c1, c2, c3, c4 int
|
||||
// arm64:`CMN`,`CSET PL`,-`CMP`
|
||||
if a+1 >= 0 {
|
||||
c1 = 1
|
||||
}
|
||||
// arm64:`CMN`,`CSET PL`,-`CMP`
|
||||
if a+b >= 0 {
|
||||
c2 = 1
|
||||
}
|
||||
// arm64:`CMN`,`CSET PL`,-`CMP`
|
||||
if a*b+c >= 0 {
|
||||
c3 = 1
|
||||
}
|
||||
// arm64:`CMP`,`CSET PL`,-`CMN`
|
||||
if a-b*c >= 0 {
|
||||
c4 = 1
|
||||
}
|
||||
return c1 + c2 + c3 + c4
|
||||
}
|
||||
|
||||
func cmp1(val string) bool {
|
||||
var z string
|
||||
// amd64:-".*memequal"
|
||||
return z == val
|
||||
}
|
||||
|
||||
func cmp2(val string) bool {
|
||||
var z string
|
||||
// amd64:-".*memequal"
|
||||
return val == z
|
||||
}
|
||||
|
||||
func cmp3(val string) bool {
|
||||
z := "food"
|
||||
// amd64:-".*memequal"
|
||||
return z == val
|
||||
}
|
||||
|
||||
func cmp4(val string) bool {
|
||||
z := "food"
|
||||
// amd64:-".*memequal"
|
||||
return val == z
|
||||
}
|
||||
|
||||
func cmp5[T comparable](val T) bool {
|
||||
var z T
|
||||
// amd64:-".*memequal"
|
||||
return z == val
|
||||
}
|
||||
|
||||
func cmp6[T comparable](val T) bool {
|
||||
var z T
|
||||
// amd64:-".*memequal"
|
||||
return val == z
|
||||
}
|
||||
|
||||
func cmp7() {
|
||||
cmp5[string]("") // force instantiation
|
||||
cmp6[string]("") // force instantiation
|
||||
}
|
||||
|
||||
type Point struct {
|
||||
X, Y int
|
||||
}
|
||||
|
||||
// invertLessThanNoov checks (LessThanNoov (InvertFlags x)) is lowered as
|
||||
// CMP, CSET, CSEL instruction sequence. InvertFlags are only generated under
|
||||
// certain conditions, see canonLessThan, so if the code below does not
|
||||
// generate an InvertFlags OP, this check may fail.
|
||||
func invertLessThanNoov(p1, p2, p3 Point) bool {
|
||||
// arm64:`CMP`,`CSET`,`CSEL`
|
||||
return (p1.X-p3.X)*(p2.Y-p3.Y)-(p2.X-p3.X)*(p1.Y-p3.Y) < 0
|
||||
}
|
||||
|
||||
func cmpstring1(x, y string) int {
|
||||
// amd64:".*cmpstring"
|
||||
if x < y {
|
||||
return -1
|
||||
}
|
||||
// amd64:-".*cmpstring"
|
||||
if x > y {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func cmpstring2(x, y string) int {
|
||||
// We want to fail if there are two calls to cmpstring.
|
||||
// They will both have the same line number, so a test
|
||||
// like in cmpstring1 will not work. Instead, we
|
||||
// look for spill/restore instructions, which only
|
||||
// need to exist if there are 2 calls.
|
||||
//amd64:-`MOVQ .*\(SP\)`
|
||||
return cmp.Compare(x, y)
|
||||
}
|
||||
529
test/codegen/condmove.go
Normal file
529
test/codegen/condmove.go
Normal file
@@ -0,0 +1,529 @@
|
||||
// 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
|
||||
|
||||
func cmovint(c int) int {
|
||||
x := c + 4
|
||||
if x < 0 {
|
||||
x = 182
|
||||
}
|
||||
// amd64:"CMOVQLT"
|
||||
// arm64:"CSEL LT"
|
||||
// ppc64x:"ISEL [$]0"
|
||||
// wasm:"Select"
|
||||
return x
|
||||
}
|
||||
|
||||
func cmovchan(x, y chan int) chan int {
|
||||
if x != y {
|
||||
x = y
|
||||
}
|
||||
// amd64:"CMOVQNE"
|
||||
// arm64:"CSEL NE"
|
||||
// ppc64x:"ISEL [$]2"
|
||||
// wasm:"Select"
|
||||
return x
|
||||
}
|
||||
|
||||
func cmovuintptr(x, y uintptr) uintptr {
|
||||
if x < y {
|
||||
x = -y
|
||||
}
|
||||
// amd64:"CMOVQ(HI|CS)"
|
||||
// arm64:"CSNEG LS"
|
||||
// ppc64x:"ISEL [$]1"
|
||||
// wasm:"Select"
|
||||
return x
|
||||
}
|
||||
|
||||
func cmov32bit(x, y uint32) uint32 {
|
||||
if x < y {
|
||||
x = -y
|
||||
}
|
||||
// amd64:"CMOVL(HI|CS)"
|
||||
// arm64:"CSNEG (LS|HS)"
|
||||
// ppc64x:"ISEL [$]1"
|
||||
// wasm:"Select"
|
||||
return x
|
||||
}
|
||||
|
||||
func cmov16bit(x, y uint16) uint16 {
|
||||
if x < y {
|
||||
x = -y
|
||||
}
|
||||
// amd64:"CMOVW(HI|CS)"
|
||||
// arm64:"CSNEG (LS|HS)"
|
||||
// ppc64x:"ISEL [$][01]"
|
||||
// wasm:"Select"
|
||||
return x
|
||||
}
|
||||
|
||||
// Floating point comparison. For EQ/NE, we must
|
||||
// generate special code to handle NaNs.
|
||||
func cmovfloateq(x, y float64) int {
|
||||
a := 128
|
||||
if x == y {
|
||||
a = 256
|
||||
}
|
||||
// amd64:"CMOVQNE" "CMOVQPC"
|
||||
// arm64:"CSEL EQ"
|
||||
// ppc64x:"ISEL [$]2"
|
||||
// wasm:"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
func cmovfloatne(x, y float64) int {
|
||||
a := 128
|
||||
if x != y {
|
||||
a = 256
|
||||
}
|
||||
// amd64:"CMOVQNE" "CMOVQPS"
|
||||
// arm64:"CSEL NE"
|
||||
// ppc64x:"ISEL [$]2"
|
||||
// wasm:"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func frexp(f float64) (frac float64, exp int) {
|
||||
return 1.0, 4
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func ldexp(frac float64, exp int) float64 {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
// Generate a CMOV with a floating comparison and integer move.
|
||||
func cmovfloatint2(x, y float64) float64 {
|
||||
yfr, yexp := 4.0, 5
|
||||
|
||||
r := x
|
||||
for r >= y {
|
||||
rfr, rexp := frexp(r)
|
||||
if rfr < yfr {
|
||||
rexp = rexp - 42
|
||||
}
|
||||
// amd64:"CMOVQHI"
|
||||
// arm64:"CSEL MI"
|
||||
// ppc64x:"ISEL [$]0"
|
||||
// wasm:"Select"
|
||||
r = r - ldexp(y, rexp-yexp)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func cmovloaded(x [4]int, y int) int {
|
||||
if x[2] != 0 {
|
||||
y = x[2]
|
||||
} else {
|
||||
y = y >> 2
|
||||
}
|
||||
// amd64:"CMOVQNE"
|
||||
// arm64:"CSEL NE"
|
||||
// ppc64x:"ISEL [$]2"
|
||||
// wasm:"Select"
|
||||
return y
|
||||
}
|
||||
|
||||
func cmovuintptr2(x, y uintptr) uintptr {
|
||||
a := x * 2
|
||||
if a == 0 {
|
||||
a = 256
|
||||
}
|
||||
// amd64:"CMOVQEQ"
|
||||
// arm64:"CSEL EQ"
|
||||
// ppc64x:"ISEL [$]2"
|
||||
// wasm:"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
// Floating point CMOVs are not supported by amd64/arm64/ppc64x
|
||||
func cmovfloatmove(x, y int) float64 {
|
||||
a := 1.0
|
||||
if x <= y {
|
||||
a = 2.0
|
||||
}
|
||||
// amd64:-"CMOV"
|
||||
// arm64:-"CSEL"
|
||||
// ppc64x:-"ISEL"
|
||||
// wasm:-"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
// On amd64, the following patterns trigger comparison inversion.
|
||||
// Test that we correctly invert the CMOV condition
|
||||
var gsink int64
|
||||
var gusink uint64
|
||||
|
||||
func cmovinvert1(x, y int64) int64 {
|
||||
if x < gsink {
|
||||
y = -y
|
||||
}
|
||||
// amd64:"CMOVQGT"
|
||||
return y
|
||||
}
|
||||
func cmovinvert2(x, y int64) int64 {
|
||||
if x <= gsink {
|
||||
y = -y
|
||||
}
|
||||
// amd64:"CMOVQGE"
|
||||
return y
|
||||
}
|
||||
func cmovinvert3(x, y int64) int64 {
|
||||
if x == gsink {
|
||||
y = -y
|
||||
}
|
||||
// amd64:"CMOVQEQ"
|
||||
return y
|
||||
}
|
||||
func cmovinvert4(x, y int64) int64 {
|
||||
if x != gsink {
|
||||
y = -y
|
||||
}
|
||||
// amd64:"CMOVQNE"
|
||||
return y
|
||||
}
|
||||
func cmovinvert5(x, y uint64) uint64 {
|
||||
if x > gusink {
|
||||
y = -y
|
||||
}
|
||||
// amd64:"CMOVQCS"
|
||||
return y
|
||||
}
|
||||
func cmovinvert6(x, y uint64) uint64 {
|
||||
if x >= gusink {
|
||||
y = -y
|
||||
}
|
||||
// amd64:"CMOVQLS"
|
||||
return y
|
||||
}
|
||||
|
||||
func cmovload(a []int, i int, b bool) int {
|
||||
if b {
|
||||
i += 42
|
||||
}
|
||||
// See issue 26306
|
||||
// amd64:-"CMOVQNE"
|
||||
return a[i]
|
||||
}
|
||||
|
||||
func cmovstore(a []int, i int, b bool) {
|
||||
if b {
|
||||
i += 42
|
||||
}
|
||||
// amd64:"CMOVQNE"
|
||||
a[i] = 7
|
||||
}
|
||||
|
||||
var r0, r1, r2, r3, r4, r5 int
|
||||
|
||||
func cmovinc(cond bool, a, b, c int) {
|
||||
var x0, x1 int
|
||||
|
||||
if cond {
|
||||
x0 = a
|
||||
} else {
|
||||
x0 = b + 1
|
||||
}
|
||||
// arm64:"CSINC NE", -"CSEL"
|
||||
r0 = x0
|
||||
|
||||
if cond {
|
||||
x1 = b + 1
|
||||
} else {
|
||||
x1 = a
|
||||
}
|
||||
// arm64:"CSINC EQ", -"CSEL"
|
||||
r1 = x1
|
||||
|
||||
if cond {
|
||||
c++
|
||||
}
|
||||
// arm64:"CSINC EQ", -"CSEL"
|
||||
r2 = c
|
||||
}
|
||||
|
||||
func cmovinv(cond bool, a, b int) {
|
||||
var x0, x1 int
|
||||
|
||||
if cond {
|
||||
x0 = a
|
||||
} else {
|
||||
x0 = ^b
|
||||
}
|
||||
// arm64:"CSINV NE", -"CSEL"
|
||||
r0 = x0
|
||||
|
||||
if cond {
|
||||
x1 = ^b
|
||||
} else {
|
||||
x1 = a
|
||||
}
|
||||
// arm64:"CSINV EQ", -"CSEL"
|
||||
r1 = x1
|
||||
}
|
||||
|
||||
func cmovneg(cond bool, a, b, c int) {
|
||||
var x0, x1 int
|
||||
|
||||
if cond {
|
||||
x0 = a
|
||||
} else {
|
||||
x0 = -b
|
||||
}
|
||||
// arm64:"CSNEG NE", -"CSEL"
|
||||
r0 = x0
|
||||
|
||||
if cond {
|
||||
x1 = -b
|
||||
} else {
|
||||
x1 = a
|
||||
}
|
||||
// arm64:"CSNEG EQ", -"CSEL"
|
||||
r1 = x1
|
||||
}
|
||||
|
||||
func cmovsetm(cond bool, x int) {
|
||||
var x0, x1 int
|
||||
|
||||
if cond {
|
||||
x0 = -1
|
||||
} else {
|
||||
x0 = 0
|
||||
}
|
||||
// arm64:"CSETM NE", -"CSEL"
|
||||
r0 = x0
|
||||
|
||||
if cond {
|
||||
x1 = 0
|
||||
} else {
|
||||
x1 = -1
|
||||
}
|
||||
// arm64:"CSETM EQ", -"CSEL"
|
||||
r1 = x1
|
||||
}
|
||||
|
||||
func cmovFcmp0(s, t float64, a, b int) {
|
||||
var x0, x1, x2, x3, x4, x5 int
|
||||
|
||||
if s < t {
|
||||
x0 = a
|
||||
} else {
|
||||
x0 = b + 1
|
||||
}
|
||||
// arm64:"CSINC MI", -"CSEL"
|
||||
r0 = x0
|
||||
|
||||
if s <= t {
|
||||
x1 = a
|
||||
} else {
|
||||
x1 = ^b
|
||||
}
|
||||
// arm64:"CSINV LS", -"CSEL"
|
||||
r1 = x1
|
||||
|
||||
if s > t {
|
||||
x2 = a
|
||||
} else {
|
||||
x2 = -b
|
||||
}
|
||||
// arm64:"CSNEG MI", -"CSEL"
|
||||
r2 = x2
|
||||
|
||||
if s >= t {
|
||||
x3 = -1
|
||||
} else {
|
||||
x3 = 0
|
||||
}
|
||||
// arm64:"CSETM LS", -"CSEL"
|
||||
r3 = x3
|
||||
|
||||
if s == t {
|
||||
x4 = a
|
||||
} else {
|
||||
x4 = b + 1
|
||||
}
|
||||
// arm64:"CSINC EQ", -"CSEL"
|
||||
r4 = x4
|
||||
|
||||
if s != t {
|
||||
x5 = a
|
||||
} else {
|
||||
x5 = b + 1
|
||||
}
|
||||
// arm64:"CSINC NE", -"CSEL"
|
||||
r5 = x5
|
||||
}
|
||||
|
||||
func cmovFcmp1(s, t float64, a, b int) {
|
||||
var x0, x1, x2, x3, x4, x5 int
|
||||
|
||||
if s < t {
|
||||
x0 = b + 1
|
||||
} else {
|
||||
x0 = a
|
||||
}
|
||||
// arm64:"CSINC PL", -"CSEL"
|
||||
r0 = x0
|
||||
|
||||
if s <= t {
|
||||
x1 = ^b
|
||||
} else {
|
||||
x1 = a
|
||||
}
|
||||
// arm64:"CSINV HI", -"CSEL"
|
||||
r1 = x1
|
||||
|
||||
if s > t {
|
||||
x2 = -b
|
||||
} else {
|
||||
x2 = a
|
||||
}
|
||||
// arm64:"CSNEG PL", -"CSEL"
|
||||
r2 = x2
|
||||
|
||||
if s >= t {
|
||||
x3 = 0
|
||||
} else {
|
||||
x3 = -1
|
||||
}
|
||||
// arm64:"CSETM HI", -"CSEL"
|
||||
r3 = x3
|
||||
|
||||
if s == t {
|
||||
x4 = b + 1
|
||||
} else {
|
||||
x4 = a
|
||||
}
|
||||
// arm64:"CSINC NE", -"CSEL"
|
||||
r4 = x4
|
||||
|
||||
if s != t {
|
||||
x5 = b + 1
|
||||
} else {
|
||||
x5 = a
|
||||
}
|
||||
// arm64:"CSINC EQ", -"CSEL"
|
||||
r5 = x5
|
||||
}
|
||||
|
||||
func cmovzero1(c bool) int {
|
||||
var x int
|
||||
if c {
|
||||
x = 182
|
||||
}
|
||||
// loong64:"MASKEQZ", -"MASKNEZ"
|
||||
return x
|
||||
}
|
||||
|
||||
func cmovzero2(c bool) int {
|
||||
var x int
|
||||
if !c {
|
||||
x = 182
|
||||
}
|
||||
// loong64:"MASKNEZ", -"MASKEQZ"
|
||||
return x
|
||||
}
|
||||
|
||||
// Conditionally selecting between a value or 0 can be done without
|
||||
// an extra load of 0 to a register on PPC64 by using R0 (which always
|
||||
// holds the value $0) instead. Verify both cases where either arg1
|
||||
// or arg2 is zero.
|
||||
func cmovzeroreg0(a, b int) int {
|
||||
x := 0
|
||||
if a == b {
|
||||
x = a
|
||||
}
|
||||
// ppc64x:"ISEL [$]2, R[0-9]+, R0, R[0-9]+"
|
||||
return x
|
||||
}
|
||||
|
||||
func cmovzeroreg1(a, b int) int {
|
||||
x := a
|
||||
if a == b {
|
||||
x = 0
|
||||
}
|
||||
// ppc64x:"ISEL [$]2, R0, R[0-9]+, R[0-9]+"
|
||||
return x
|
||||
}
|
||||
|
||||
func cmovmathadd(a uint, b bool) uint {
|
||||
if b {
|
||||
a++
|
||||
}
|
||||
// amd64:"ADDQ", -"CMOV"
|
||||
// arm64:"CSINC", -"CSEL"
|
||||
// ppc64x:"ADD", -"ISEL"
|
||||
// wasm:"I64Add", -"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
func cmovmathsub(a uint, b bool) uint {
|
||||
if b {
|
||||
a--
|
||||
}
|
||||
// amd64:"SUBQ", -"CMOV"
|
||||
// arm64:"SUB", -"CSEL"
|
||||
// ppc64x:"SUB", -"ISEL"
|
||||
// wasm:"I64Sub", -"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
func cmovmathdouble(a uint, b bool) uint {
|
||||
if b {
|
||||
a *= 2
|
||||
}
|
||||
// amd64:"SHL", -"CMOV"
|
||||
// amd64/v3:"SHL", -"CMOV", -"MOV"
|
||||
// arm64:"LSL", -"CSEL"
|
||||
// wasm:"I64Shl", -"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
func cmovmathhalvei(a int, b bool) int {
|
||||
if b {
|
||||
// For some reason the compiler attributes the shift to inside this block rather than where the Phi node is.
|
||||
// arm64:"ASR", -"CSEL"
|
||||
// wasm:"I64ShrS", -"Select"
|
||||
a /= 2
|
||||
}
|
||||
// arm64:-"CSEL"
|
||||
// wasm:-"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
func cmovmathhalveu(a uint, b bool) uint {
|
||||
if b {
|
||||
a /= 2
|
||||
}
|
||||
// amd64:"SHR", -"CMOV"
|
||||
// amd64/v3:"SHR", -"CMOV", -"MOV"
|
||||
// arm64:"LSR", -"CSEL"
|
||||
// wasm:"I64ShrU", -"Select"
|
||||
return a
|
||||
}
|
||||
|
||||
func branchlessBoolToUint8(b bool) (r uint8) {
|
||||
if b {
|
||||
r = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func cmovFromMulFromFlags64(x uint64, b bool) uint64 {
|
||||
// amd64:-"MOVB.ZX"
|
||||
r := uint64(branchlessBoolToUint8(b))
|
||||
// amd64:"CMOV",-"MOVB.ZX",-"MUL"
|
||||
return x * r
|
||||
}
|
||||
func cmovFromMulFromFlags64sext(x int64, b bool) int64 {
|
||||
// amd64:-"MOVB.ZX"
|
||||
r := int64(int8(branchlessBoolToUint8(b)))
|
||||
// amd64:"CMOV",-"MOVB.ZX",-"MUL"
|
||||
return x * r
|
||||
}
|
||||
35
test/codegen/constants.go
Normal file
35
test/codegen/constants.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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
|
||||
|
||||
// A uint16 or sint16 constant shifted left.
|
||||
func shifted16BitConstants() (out [64]uint64) {
|
||||
// ppc64x: "MOVD [$]8193,", "SLD [$]27,"
|
||||
out[0] = 0x0000010008000000
|
||||
// ppc64x: "MOVD [$]-32767", "SLD [$]26,"
|
||||
out[1] = 0xFFFFFE0004000000
|
||||
// ppc64x: "MOVD [$]-1", "SLD [$]48,"
|
||||
out[2] = 0xFFFF000000000000
|
||||
// ppc64x: "MOVD [$]65535", "SLD [$]44,"
|
||||
out[3] = 0x0FFFF00000000000
|
||||
return
|
||||
}
|
||||
|
||||
// A contiguous set of 1 bits, potentially wrapping.
|
||||
func contiguousMaskConstants() (out [64]uint64) {
|
||||
// ppc64x: "MOVD [$]-1", "RLDC R[0-9]+, [$]44, [$]63,"
|
||||
out[0] = 0xFFFFF00000000001
|
||||
// ppc64x: "MOVD [$]-1", "RLDC R[0-9]+, [$]43, [$]63,"
|
||||
out[1] = 0xFFFFF80000000001
|
||||
// ppc64x: "MOVD [$]-1", "RLDC R[0-9]+, [$]43, [$]4,"
|
||||
out[2] = 0x0FFFF80000000000
|
||||
// ppc64x/power8: "MOVD [$]-1", "RLDC R[0-9]+, [$]33, [$]63,"
|
||||
// ppc64x/power9: "MOVD [$]-1", "RLDC R[0-9]+, [$]33, [$]63,"
|
||||
// ppc64x/power10: "MOVD [$]-8589934591,"
|
||||
out[3] = 0xFFFFFFFE00000001
|
||||
return
|
||||
}
|
||||
162
test/codegen/copy.go
Normal file
162
test/codegen/copy.go
Normal file
@@ -0,0 +1,162 @@
|
||||
// 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 "runtime"
|
||||
|
||||
// Check small copies are replaced with moves.
|
||||
|
||||
func movesmall4() {
|
||||
x := [...]byte{1, 2, 3, 4}
|
||||
// 386:-".*memmove"
|
||||
// amd64:-".*memmove"
|
||||
// arm:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(x[1:], x[:])
|
||||
}
|
||||
|
||||
func movesmall7() {
|
||||
x := [...]byte{1, 2, 3, 4, 5, 6, 7}
|
||||
// 386:-".*memmove"
|
||||
// amd64:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(x[1:], x[:])
|
||||
}
|
||||
|
||||
func movesmall16() {
|
||||
x := [...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
|
||||
// amd64:-".*memmove"
|
||||
// ppc64x:".*memmove"
|
||||
copy(x[1:], x[:])
|
||||
}
|
||||
|
||||
var x [256]byte
|
||||
|
||||
// Check that large disjoint copies are replaced with moves.
|
||||
|
||||
func moveDisjointStack32() {
|
||||
var s [32]byte
|
||||
// ppc64x:-".*memmove"
|
||||
// ppc64x/power8:"LXVD2X" -"ADD" -"BC"
|
||||
// ppc64x/power9:"LXV" -"LXVD2X" -"ADD" -"BC"
|
||||
copy(s[:], x[:32])
|
||||
runtime.KeepAlive(&s)
|
||||
}
|
||||
|
||||
func moveDisjointStack64() {
|
||||
var s [96]byte
|
||||
// ppc64x:-".*memmove"
|
||||
// ppc64x/power8:"LXVD2X" "ADD" "BC"
|
||||
// ppc64x/power9:"LXV" -"LXVD2X" -"ADD" -"BC"
|
||||
copy(s[:], x[:96])
|
||||
runtime.KeepAlive(&s)
|
||||
}
|
||||
|
||||
func moveDisjointStack() {
|
||||
var s [256]byte
|
||||
// s390x:-".*memmove"
|
||||
// amd64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
// ppc64x/power8:"LXVD2X"
|
||||
// ppc64x/power9:"LXV" -"LXVD2X"
|
||||
copy(s[:], x[:])
|
||||
runtime.KeepAlive(&s)
|
||||
}
|
||||
|
||||
func moveDisjointArg(b *[256]byte) {
|
||||
var s [256]byte
|
||||
// s390x:-".*memmove"
|
||||
// amd64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
// ppc64x/power8:"LXVD2X"
|
||||
// ppc64x/power9:"LXV" -"LXVD2X"
|
||||
copy(s[:], b[:])
|
||||
runtime.KeepAlive(&s)
|
||||
}
|
||||
|
||||
func moveDisjointNoOverlap(a *[256]byte) {
|
||||
// s390x:-".*memmove"
|
||||
// amd64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
// ppc64x/power8:"LXVD2X"
|
||||
// ppc64x/power9:"LXV" -"LXVD2X"
|
||||
copy(a[:], a[128:])
|
||||
}
|
||||
|
||||
// Check arch-specific memmove lowering. See issue 41662 fot details
|
||||
|
||||
func moveArchLowering1(b []byte, x *[1]byte) {
|
||||
_ = b[1]
|
||||
// amd64:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// loong64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(b, x[:])
|
||||
}
|
||||
|
||||
func moveArchLowering2(b []byte, x *[2]byte) {
|
||||
_ = b[2]
|
||||
// amd64:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// loong64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(b, x[:])
|
||||
}
|
||||
|
||||
func moveArchLowering4(b []byte, x *[4]byte) {
|
||||
_ = b[4]
|
||||
// amd64:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// loong64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(b, x[:])
|
||||
}
|
||||
|
||||
func moveArchLowering8(b []byte, x *[8]byte) {
|
||||
_ = b[8]
|
||||
// amd64:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(b, x[:])
|
||||
}
|
||||
|
||||
func moveArchLowering16(b []byte, x *[16]byte) {
|
||||
_ = b[16]
|
||||
// amd64:-".*memmove"
|
||||
copy(b, x[:])
|
||||
}
|
||||
|
||||
// Check that no branches are generated when the pointers are [not] equal.
|
||||
|
||||
func ptrEqual() {
|
||||
// amd64:-"JEQ" -"JNE"
|
||||
// ppc64x:-"BEQ" -"BNE"
|
||||
// s390x:-"BEQ" -"BNE"
|
||||
copy(x[:], x[:])
|
||||
}
|
||||
|
||||
func ptrOneOffset() {
|
||||
// amd64:-"JEQ" -"JNE"
|
||||
// ppc64x:-"BEQ" -"BNE"
|
||||
// s390x:-"BEQ" -"BNE"
|
||||
copy(x[1:], x[:])
|
||||
}
|
||||
|
||||
func ptrBothOffset() {
|
||||
// amd64:-"JEQ" -"JNE"
|
||||
// ppc64x:-"BEQ" -"BNE"
|
||||
// s390x:-"BEQ" -"BNE"
|
||||
copy(x[1:], x[2:])
|
||||
}
|
||||
|
||||
// Verify #62698 on PPC64.
|
||||
func noMaskOnCopy(a []int, s string, x int) int {
|
||||
// ppc64x:-"MOVD [$]-1", -"AND"
|
||||
return a[x&^copy([]byte{}, s)]
|
||||
}
|
||||
1200
test/codegen/divmod.go
Normal file
1200
test/codegen/divmod.go
Normal file
File diff suppressed because it is too large
Load Diff
315
test/codegen/floats.go
Normal file
315
test/codegen/floats.go
Normal file
@@ -0,0 +1,315 @@
|
||||
// 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 "math"
|
||||
|
||||
// This file contains codegen tests related to arithmetic
|
||||
// simplifications and optimizations on float types.
|
||||
// For codegen tests on integer types, see arithmetic.go.
|
||||
|
||||
// --------------------- //
|
||||
// Strength-reduce //
|
||||
// --------------------- //
|
||||
|
||||
func Mul2(f float64) float64 {
|
||||
// 386/sse2:"ADDSD" -"MULSD"
|
||||
// amd64:"ADDSD" -"MULSD"
|
||||
// arm/7:"ADDD" -"MULD"
|
||||
// arm64:"FADDD" -"FMULD"
|
||||
// loong64:"ADDD" -"MULD"
|
||||
// ppc64x:"FADD" -"FMUL"
|
||||
// riscv64:"FADDD" -"FMULD"
|
||||
return f * 2.0
|
||||
}
|
||||
|
||||
func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
|
||||
// 386/sse2:"MULSD" -"DIVSD"
|
||||
// amd64:"MULSD" -"DIVSD"
|
||||
// arm/7:"MULD" -"DIVD"
|
||||
// arm64:"FMULD" -"FDIVD"
|
||||
// loong64:"MULD" -"DIVD"
|
||||
// ppc64x:"FMUL" -"FDIV"
|
||||
// riscv64:"FMULD" -"FDIVD"
|
||||
x := f1 / 16.0
|
||||
|
||||
// 386/sse2:"MULSD" -"DIVSD"
|
||||
// amd64:"MULSD" -"DIVSD"
|
||||
// arm/7:"MULD" -"DIVD"
|
||||
// arm64:"FMULD" -"FDIVD"
|
||||
// loong64:"MULD" -"DIVD"
|
||||
// ppc64x:"FMUL" -"FDIVD"
|
||||
// riscv64:"FMULD" -"FDIVD"
|
||||
y := f2 / 0.125
|
||||
|
||||
// 386/sse2:"ADDSD" -"DIVSD" -"MULSD"
|
||||
// amd64:"ADDSD" -"DIVSD" -"MULSD"
|
||||
// arm/7:"ADDD" -"MULD" -"DIVD"
|
||||
// arm64:"FADDD" -"FMULD" -"FDIVD"
|
||||
// loong64:"ADDD" -"MULD" -"DIVD"
|
||||
// ppc64x:"FADD" -"FMUL" -"FDIV"
|
||||
// riscv64:"FADDD" -"FMULD" -"FDIVD"
|
||||
z := f3 / 0.5
|
||||
|
||||
return x, y, z
|
||||
}
|
||||
|
||||
func indexLoad(b0 []float32, b1 float32, idx int) float32 {
|
||||
// arm64:`FMOVS\s\(R[0-9]+\)\(R[0-9]+<<2\),\sF[0-9]+`
|
||||
// loong64:`MOVF\s\(R[0-9]+\)\(R[0-9]+\),\sF[0-9]+`
|
||||
return b0[idx] * b1
|
||||
}
|
||||
|
||||
func indexStore(b0 []float64, b1 float64, idx int) {
|
||||
// arm64:`FMOVD\sF[0-9]+,\s\(R[0-9]+\)\(R[0-9]+<<3\)`
|
||||
// loong64:`MOVD\sF[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`
|
||||
b0[idx] = b1
|
||||
}
|
||||
|
||||
// ----------- //
|
||||
// Fused //
|
||||
// ----------- //
|
||||
|
||||
func FusedAdd32(x, y, z float32) float32 {
|
||||
// s390x:"FMADDS "
|
||||
// ppc64x:"FMADDS "
|
||||
// arm64:"FMADDS"
|
||||
// loong64:"FMADDF "
|
||||
// riscv64:"FMADDS "
|
||||
// amd64/v3:"VFMADD231SS "
|
||||
return x*y + z
|
||||
}
|
||||
|
||||
func FusedSub32_a(x, y, z float32) float32 {
|
||||
// s390x:"FMSUBS "
|
||||
// ppc64x:"FMSUBS "
|
||||
// riscv64:"FMSUBS "
|
||||
// loong64:"FMSUBF "
|
||||
return x*y - z
|
||||
}
|
||||
|
||||
func FusedSub32_b(x, y, z float32) float32 {
|
||||
// arm64:"FMSUBS"
|
||||
// loong64:"FNMSUBF "
|
||||
// riscv64:"FNMSUBS "
|
||||
return z - x*y
|
||||
}
|
||||
|
||||
func FusedAdd64(x, y, z float64) float64 {
|
||||
// s390x:"FMADD "
|
||||
// ppc64x:"FMADD "
|
||||
// arm64:"FMADDD"
|
||||
// loong64:"FMADDD "
|
||||
// riscv64:"FMADDD "
|
||||
// amd64/v3:"VFMADD231SD "
|
||||
return x*y + z
|
||||
}
|
||||
|
||||
func FusedSub64_a(x, y, z float64) float64 {
|
||||
// s390x:"FMSUB "
|
||||
// ppc64x:"FMSUB "
|
||||
// riscv64:"FMSUBD "
|
||||
// loong64:"FMSUBD "
|
||||
return x*y - z
|
||||
}
|
||||
|
||||
func FusedSub64_b(x, y, z float64) float64 {
|
||||
// arm64:"FMSUBD"
|
||||
// loong64:"FNMSUBD "
|
||||
// riscv64:"FNMSUBD "
|
||||
return z - x*y
|
||||
}
|
||||
|
||||
func Cmp(f float64) bool {
|
||||
// arm64:"FCMPD" "(BGT|BLE|BMI|BPL)" -"CSET GT" -"CBZ"
|
||||
return f > 4 || f < -4
|
||||
}
|
||||
|
||||
func CmpZero64(f float64) bool {
|
||||
// s390x:"LTDBR" -"FCMPU"
|
||||
return f <= 0
|
||||
}
|
||||
|
||||
func CmpZero32(f float32) bool {
|
||||
// s390x:"LTEBR" -"CEBR"
|
||||
return f <= 0
|
||||
}
|
||||
|
||||
func CmpWithSub(a float64, b float64) bool {
|
||||
f := a - b
|
||||
// s390x:-"LTDBR"
|
||||
return f <= 0
|
||||
}
|
||||
|
||||
func CmpWithAdd(a float64, b float64) bool {
|
||||
f := a + b
|
||||
// s390x:-"LTDBR"
|
||||
return f <= 0
|
||||
}
|
||||
|
||||
// ---------------- //
|
||||
// Non-floats //
|
||||
// ---------------- //
|
||||
|
||||
func ArrayZero() [16]byte {
|
||||
// amd64:"MOVUPS"
|
||||
var a [16]byte
|
||||
return a
|
||||
}
|
||||
|
||||
func ArrayCopy(a [16]byte) (b [16]byte) {
|
||||
// amd64:"MOVUPS"
|
||||
b = a
|
||||
return
|
||||
}
|
||||
|
||||
// ---------------- //
|
||||
// Float Min/Max //
|
||||
// ---------------- //
|
||||
|
||||
func Float64Min(a, b float64) float64 {
|
||||
// amd64:"MINSD"
|
||||
// arm64:"FMIND"
|
||||
// loong64:"FMIND"
|
||||
// riscv64:"FMIN"
|
||||
// ppc64/power9:"XSMINJDP"
|
||||
// ppc64/power10:"XSMINJDP"
|
||||
// s390x: "WFMINDB"
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func Float64Max(a, b float64) float64 {
|
||||
// amd64:"MINSD"
|
||||
// arm64:"FMAXD"
|
||||
// loong64:"FMAXD"
|
||||
// riscv64:"FMAX"
|
||||
// ppc64/power9:"XSMAXJDP"
|
||||
// ppc64/power10:"XSMAXJDP"
|
||||
// s390x: "WFMAXDB"
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
func Float32Min(a, b float32) float32 {
|
||||
// amd64:"MINSS"
|
||||
// arm64:"FMINS"
|
||||
// loong64:"FMINF"
|
||||
// riscv64:"FMINS"
|
||||
// ppc64/power9:"XSMINJDP"
|
||||
// ppc64/power10:"XSMINJDP"
|
||||
// s390x: "WFMINSB"
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func Float32Max(a, b float32) float32 {
|
||||
// amd64:"MINSS"
|
||||
// arm64:"FMAXS"
|
||||
// loong64:"FMAXF"
|
||||
// riscv64:"FMAXS"
|
||||
// ppc64/power9:"XSMAXJDP"
|
||||
// ppc64/power10:"XSMAXJDP"
|
||||
// s390x: "WFMAXSB"
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
// ------------------------ //
|
||||
// Constant Optimizations //
|
||||
// ------------------------ //
|
||||
|
||||
func Float32ConstantZero() float32 {
|
||||
// arm64:"FMOVS ZR,"
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func Float32ConstantChipFloat() float32 {
|
||||
// arm64:"FMOVS [$]\\(2\\.25\\),"
|
||||
return 2.25
|
||||
}
|
||||
|
||||
func Float32Constant() float32 {
|
||||
// arm64:"FMOVS [$]f32\\.42440000\\(SB\\)"
|
||||
// ppc64x/power8:"FMOVS [$]f32\\.42440000\\(SB\\)"
|
||||
// ppc64x/power9:"FMOVS [$]f32\\.42440000\\(SB\\)"
|
||||
// ppc64x/power10:"XXSPLTIDP [$]1111752704,"
|
||||
return 49.0
|
||||
}
|
||||
|
||||
func Float64ConstantZero() float64 {
|
||||
// arm64:"FMOVD ZR,"
|
||||
return 0.0
|
||||
}
|
||||
|
||||
func Float64ConstantChipFloat() float64 {
|
||||
// arm64:"FMOVD [$]\\(2\\.25\\),"
|
||||
return 2.25
|
||||
}
|
||||
|
||||
func Float64Constant() float64 {
|
||||
// arm64:"FMOVD [$]f64\\.4048800000000000\\(SB\\)"
|
||||
// ppc64x/power8:"FMOVD [$]f64\\.4048800000000000\\(SB\\)"
|
||||
// ppc64x/power9:"FMOVD [$]f64\\.4048800000000000\\(SB\\)"
|
||||
// ppc64x/power10:"XXSPLTIDP [$]1111752704,"
|
||||
return 49.0
|
||||
}
|
||||
|
||||
func Float32DenormalConstant() float32 {
|
||||
// ppc64x:"FMOVS [$]f32\\.00400000\\(SB\\)"
|
||||
return 0x1p-127
|
||||
}
|
||||
|
||||
// A float64 constant which can be exactly represented as a
|
||||
// denormal float32 value. On ppc64x, denormal values cannot
|
||||
// be used with XXSPLTIDP.
|
||||
func Float64DenormalFloat32Constant() float64 {
|
||||
// ppc64x:"FMOVD [$]f64\\.3800000000000000\\(SB\\)"
|
||||
return 0x1p-127
|
||||
}
|
||||
|
||||
func Float32ConstantStore(p *float32) {
|
||||
// amd64:"MOVL [$]1085133554"
|
||||
// riscv64: "MOVF [$]f32.40add2f2"
|
||||
*p = 5.432
|
||||
}
|
||||
|
||||
func Float64ConstantStore(p *float64) {
|
||||
// amd64: "MOVQ [$]4617801906721357038"
|
||||
// riscv64: "MOVD [$]f64.4015ba5e353f7cee"
|
||||
*p = 5.432
|
||||
}
|
||||
|
||||
// ------------------------ //
|
||||
// Subnormal tests //
|
||||
// ------------------------ //
|
||||
|
||||
func isSubnormal(x float64) bool {
|
||||
// riscv64:"FCLASSD" -"FABSD"
|
||||
return math.Abs(x) < 2.2250738585072014e-308
|
||||
}
|
||||
|
||||
func isNormal(x float64) bool {
|
||||
// riscv64:"FCLASSD" -"FABSD"
|
||||
return math.Abs(x) >= 0x1p-1022
|
||||
}
|
||||
|
||||
func isPosSubnormal(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x > 0 && x < 2.2250738585072014e-308
|
||||
}
|
||||
|
||||
func isNegSubnormal(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x < 0 && x > -0x1p-1022
|
||||
}
|
||||
|
||||
func isPosNormal(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x >= 2.2250738585072014e-308
|
||||
}
|
||||
|
||||
func isNegNormal(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x <= -2.2250738585072014e-308
|
||||
}
|
||||
418
test/codegen/fuse.go
Normal file
418
test/codegen/fuse.go
Normal file
@@ -0,0 +1,418 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2019 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 "math"
|
||||
|
||||
// Notes:
|
||||
// - these examples use channels to provide a source of
|
||||
// unknown values that cannot be optimized away
|
||||
// - these examples use for loops to force branches
|
||||
// backward (predicted taken)
|
||||
|
||||
// ---------------------------------- //
|
||||
// signed integer range (conjunction) //
|
||||
// ---------------------------------- //
|
||||
|
||||
func si1c(c <-chan int64) {
|
||||
// amd64:"CMPQ .+, [$]256"
|
||||
// s390x:"CLGIJ [$]12, R[0-9]+, [$]255"
|
||||
for x := <-c; x >= 0 && x < 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si2c(c <-chan int32) {
|
||||
// amd64:"CMPL .+, [$]256"
|
||||
// s390x:"CLIJ [$]12, R[0-9]+, [$]255"
|
||||
for x := <-c; x >= 0 && x < 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si3c(c <-chan int16) {
|
||||
// amd64:"CMPW .+, [$]256"
|
||||
// s390x:"CLIJ [$]12, R[0-9]+, [$]255"
|
||||
for x := <-c; x >= 0 && x < 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si4c(c <-chan int8) {
|
||||
// amd64:"CMPB .+, [$]10"
|
||||
// s390x:"CLIJ [$]4, R[0-9]+, [$]10"
|
||||
for x := <-c; x >= 0 && x < 10; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si5c(c <-chan int64) {
|
||||
// amd64:"CMPQ .+, [$]251" "ADDQ [$]-5,"
|
||||
// s390x:"CLGIJ [$]4, R[0-9]+, [$]251" "ADD [$]-5,"
|
||||
for x := <-c; x < 256 && x > 4; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si6c(c <-chan int32) {
|
||||
// amd64:"CMPL .+, [$]255" "DECL "
|
||||
// s390x:"CLIJ [$]12, R[0-9]+, [$]255" "ADDW [$]-1,"
|
||||
for x := <-c; x > 0 && x <= 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si7c(c <-chan int16) {
|
||||
// amd64:"CMPW .+, [$]60" "ADDL [$]10,"
|
||||
// s390x:"CLIJ [$]12, R[0-9]+, [$]60" "ADDW [$]10,"
|
||||
for x := <-c; x >= -10 && x <= 50; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si8c(c <-chan int8) {
|
||||
// amd64:"CMPB .+, [$]126" "ADDL [$]126,"
|
||||
// s390x:"CLIJ [$]4, R[0-9]+, [$]126" "ADDW [$]126,"
|
||||
for x := <-c; x >= -126 && x < 0; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------- //
|
||||
// signed integer range (disjunction) //
|
||||
// ---------------------------------- //
|
||||
|
||||
func si1d(c <-chan int64) {
|
||||
// amd64:"CMPQ .+, [$]256"
|
||||
// s390x:"CLGIJ [$]2, R[0-9]+, [$]255"
|
||||
for x := <-c; x < 0 || x >= 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si2d(c <-chan int32) {
|
||||
// amd64:"CMPL .+, [$]256"
|
||||
// s390x:"CLIJ [$]2, R[0-9]+, [$]255"
|
||||
for x := <-c; x < 0 || x >= 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si3d(c <-chan int16) {
|
||||
// amd64:"CMPW .+, [$]256"
|
||||
// s390x:"CLIJ [$]2, R[0-9]+, [$]255"
|
||||
for x := <-c; x < 0 || x >= 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si4d(c <-chan int8) {
|
||||
// amd64:"CMPB .+, [$]10"
|
||||
// s390x:"CLIJ [$]10, R[0-9]+, [$]10"
|
||||
for x := <-c; x < 0 || x >= 10; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si5d(c <-chan int64) {
|
||||
// amd64:"CMPQ .+, [$]251" "ADDQ [$]-5,"
|
||||
// s390x:"CLGIJ [$]10, R[0-9]+, [$]251" "ADD [$]-5,"
|
||||
for x := <-c; x >= 256 || x <= 4; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si6d(c <-chan int32) {
|
||||
// amd64:"CMPL .+, [$]255" "DECL "
|
||||
// s390x:"CLIJ [$]2, R[0-9]+, [$]255" "ADDW [$]-1,"
|
||||
for x := <-c; x <= 0 || x > 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si7d(c <-chan int16) {
|
||||
// amd64:"CMPW .+, [$]60" "ADDL [$]10,"
|
||||
// s390x:"CLIJ [$]2, R[0-9]+, [$]60" "ADDW [$]10,"
|
||||
for x := <-c; x < -10 || x > 50; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func si8d(c <-chan int8) {
|
||||
// amd64:"CMPB .+, [$]126" "ADDL [$]126,"
|
||||
// s390x:"CLIJ [$]10, R[0-9]+, [$]126" "ADDW [$]126,"
|
||||
for x := <-c; x < -126 || x >= 0; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------ //
|
||||
// unsigned integer range (conjunction) //
|
||||
// ------------------------------------ //
|
||||
|
||||
func ui1c(c <-chan uint64) {
|
||||
// amd64:"CMPQ .+, [$]251" "ADDQ [$]-5,"
|
||||
// s390x:"CLGIJ [$]4, R[0-9]+, [$]251" "ADD [$]-5,"
|
||||
for x := <-c; x < 256 && x > 4; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func ui2c(c <-chan uint32) {
|
||||
// amd64:"CMPL .+, [$]255" "DECL "
|
||||
// s390x:"CLIJ [$]12, R[0-9]+, [$]255" "ADDW [$]-1,"
|
||||
for x := <-c; x > 0 && x <= 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func ui3c(c <-chan uint16) {
|
||||
// amd64:"CMPW .+, [$]40" "ADDL [$]-10,"
|
||||
// s390x:"CLIJ [$]12, R[0-9]+, [$]40" "ADDW [$]-10,"
|
||||
for x := <-c; x >= 10 && x <= 50; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func ui4c(c <-chan uint8) {
|
||||
// amd64:"CMPB .+, [$]2" "ADDL [$]-126,"
|
||||
// s390x:"CLIJ [$]4, R[0-9]+, [$]2" "ADDW [$]-126,"
|
||||
for x := <-c; x >= 126 && x < 128; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------ //
|
||||
// unsigned integer range (disjunction) //
|
||||
// ------------------------------------ //
|
||||
|
||||
func ui1d(c <-chan uint64) {
|
||||
// amd64:"CMPQ .+, [$]251" "ADDQ [$]-5,"
|
||||
// s390x:"CLGIJ [$]10, R[0-9]+, [$]251" "ADD [$]-5,"
|
||||
for x := <-c; x >= 256 || x <= 4; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func ui2d(c <-chan uint32) {
|
||||
// amd64:"CMPL .+, [$]254" "ADDL [$]-2,"
|
||||
// s390x:"CLIJ [$]2, R[0-9]+, [$]254" "ADDW [$]-2,"
|
||||
for x := <-c; x <= 1 || x > 256; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func ui3d(c <-chan uint16) {
|
||||
// amd64:"CMPW .+, [$]40" "ADDL [$]-10,"
|
||||
// s390x:"CLIJ [$]2, R[0-9]+, [$]40" "ADDW [$]-10,"
|
||||
for x := <-c; x < 10 || x > 50; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func ui4d(c <-chan uint8) {
|
||||
// amd64:"CMPB .+, [$]2" "ADDL [$]-126,"
|
||||
// s390x:"CLIJ [$]10, R[0-9]+, [$]2" "ADDW [$]-126,"
|
||||
for x := <-c; x < 126 || x >= 128; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------ //
|
||||
// single bit difference (conjunction) //
|
||||
// ------------------------------------ //
|
||||
|
||||
func sisbc64(c <-chan int64) {
|
||||
// amd64: "ORQ [$]2,"
|
||||
// riscv64: "ORI [$]2,"
|
||||
for x := <-c; x != 4 && x != 6; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func sisbc32(c <-chan int32) {
|
||||
// amd64: "ORL [$]4,"
|
||||
// riscv64: "ORI [$]4,"
|
||||
for x := <-c; x != -1 && x != -5; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func sisbc16(c <-chan int16) {
|
||||
// amd64: "ORL [$]32,"
|
||||
// riscv64: "ORI [$]32,"
|
||||
for x := <-c; x != 16 && x != 48; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func sisbc8(c <-chan int8) {
|
||||
// amd64: "ORL [$]16,"
|
||||
// riscv64: "ORI [$]16,"
|
||||
for x := <-c; x != -15 && x != -31; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func uisbc64(c <-chan uint64) {
|
||||
// amd64: "ORQ [$]4,"
|
||||
// riscv64: "ORI [$]4,"
|
||||
for x := <-c; x != 1 && x != 5; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func uisbc32(c <-chan uint32) {
|
||||
// amd64: "ORL [$]4,"
|
||||
// riscv64: "ORI [$]4,"
|
||||
for x := <-c; x != 2 && x != 6; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func uisbc16(c <-chan uint16) {
|
||||
// amd64: "ORL [$]32,"
|
||||
// riscv64: "ORI [$]32,"
|
||||
for x := <-c; x != 16 && x != 48; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func uisbc8(c <-chan uint8) {
|
||||
// amd64: "ORL [$]64,"
|
||||
// riscv64: "ORI [$]64,"
|
||||
for x := <-c; x != 64 && x != 0; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------ //
|
||||
// single bit difference (disjunction) //
|
||||
// ------------------------------------ //
|
||||
|
||||
func sisbd64(c <-chan int64) {
|
||||
// amd64: "ORQ [$]2,"
|
||||
// riscv64: "ORI [$]2,"
|
||||
for x := <-c; x == 4 || x == 6; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func sisbd32(c <-chan int32) {
|
||||
// amd64: "ORL [$]4,"
|
||||
// riscv64: "ORI [$]4,"
|
||||
for x := <-c; x == -1 || x == -5; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func sisbd16(c <-chan int16) {
|
||||
// amd64: "ORL [$]32,"
|
||||
// riscv64: "ORI [$]32,"
|
||||
for x := <-c; x == 16 || x == 48; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func sisbd8(c <-chan int8) {
|
||||
// amd64: "ORL [$]16,"
|
||||
// riscv64: "ORI [$]16,"
|
||||
for x := <-c; x == -15 || x == -31; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func uisbd64(c <-chan uint64) {
|
||||
// amd64: "ORQ [$]4,"
|
||||
// riscv64: "ORI [$]4,"
|
||||
for x := <-c; x == 1 || x == 5; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func uisbd32(c <-chan uint32) {
|
||||
// amd64: "ORL [$]4,"
|
||||
// riscv64: "ORI [$]4,"
|
||||
for x := <-c; x == 2 || x == 6; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func uisbd16(c <-chan uint16) {
|
||||
// amd64: "ORL [$]32,"
|
||||
// riscv64: "ORI [$]32,"
|
||||
for x := <-c; x == 16 || x == 48; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func uisbd8(c <-chan uint8) {
|
||||
// amd64: "ORL [$]64,"
|
||||
// riscv64: "ORI [$]64,"
|
||||
for x := <-c; x == 64 || x == 0; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------//
|
||||
// merge NaN checks //
|
||||
// ------------------------------------ //
|
||||
|
||||
func f64NaNOrPosInf(c <-chan float64) {
|
||||
// This test assumes IsInf(x, 1) is implemented as x > MaxFloat rather than x == Inf(1).
|
||||
|
||||
// amd64:"JCS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FCLASSD" -"FLED" -"FLTD" -"FNED" -"FEQD"
|
||||
for x := <-c; math.IsNaN(x) || math.IsInf(x, 1); x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f64NaNOrNegInf(c <-chan float64) {
|
||||
// This test assumes IsInf(x, -1) is implemented as x < -MaxFloat rather than x == Inf(-1).
|
||||
|
||||
// amd64:"JCS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FCLASSD" -"FLED" -"FLTD" -"FNED" -"FEQD"
|
||||
for x := <-c; math.IsNaN(x) || math.IsInf(x, -1); x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f64NaNOrLtOne(c <-chan float64) {
|
||||
// amd64:"JCS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FLED" -"FLTD" -"FNED" -"FEQD"
|
||||
for x := <-c; math.IsNaN(x) || x < 1; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f64NaNOrLteOne(c <-chan float64) {
|
||||
// amd64:"JLS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FLTD" -"FLED" -"FNED" -"FEQD"
|
||||
for x := <-c; x <= 1 || math.IsNaN(x); x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f64NaNOrGtOne(c <-chan float64) {
|
||||
// amd64:"JCS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FLED" -"FLTD" -"FNED" -"FEQD"
|
||||
for x := <-c; math.IsNaN(x) || x > 1; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f64NaNOrGteOne(c <-chan float64) {
|
||||
// amd64:"JLS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FLTD" -"FLED" -"FNED" -"FEQD"
|
||||
for x := <-c; x >= 1 || math.IsNaN(x); x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f32NaNOrLtOne(c <-chan float32) {
|
||||
// amd64:"JCS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FLES" -"FLTS" -"FNES" -"FEQS"
|
||||
for x := <-c; x < 1 || x != x; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f32NaNOrLteOne(c <-chan float32) {
|
||||
// amd64:"JLS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FLTS" -"FLES" -"FNES" -"FEQS"
|
||||
for x := <-c; x != x || x <= 1; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f32NaNOrGtOne(c <-chan float32) {
|
||||
// amd64:"JCS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FLES" -"FLTS" -"FNES" -"FEQS"
|
||||
for x := <-c; x > 1 || x != x; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
func f32NaNOrGteOne(c <-chan float32) {
|
||||
// amd64:"JLS" -"JNE" -"JPS" -"JPC"
|
||||
// riscv64:"FLTS" -"FLES" -"FNES" -"FEQS"
|
||||
for x := <-c; x != x || x >= 1; x = <-c {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------ //
|
||||
// regressions //
|
||||
// ------------------------------------ //
|
||||
|
||||
func gte4(x uint64) bool {
|
||||
return x >= 4
|
||||
}
|
||||
|
||||
func lt20(x uint64) bool {
|
||||
return x < 20
|
||||
}
|
||||
|
||||
func issue74915(c <-chan uint64) {
|
||||
// Check that the optimization is not blocked by function inlining.
|
||||
|
||||
// amd64:"CMPQ .+, [$]16" "ADDQ [$]-4,"
|
||||
// s390x:"CLGIJ [$]4, R[0-9]+, [$]16" "ADD [$]-4,"
|
||||
for x := <-c; gte4(x) && lt20(x); x = <-c {
|
||||
}
|
||||
}
|
||||
40
test/codegen/generics.go
Normal file
40
test/codegen/generics.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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 "cmp"
|
||||
|
||||
func isNaN[T cmp.Ordered](x T) bool {
|
||||
return x != x
|
||||
}
|
||||
|
||||
func compare[T cmp.Ordered](x, y T) int {
|
||||
// amd64:-"TESTB"
|
||||
// arm64:-"MOVB"
|
||||
xNaN := isNaN(x)
|
||||
yNaN := isNaN(y)
|
||||
if xNaN {
|
||||
if yNaN {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
if yNaN {
|
||||
return +1
|
||||
}
|
||||
if x < y {
|
||||
return -1
|
||||
}
|
||||
if x > y {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func usesCompare(a, b int) int {
|
||||
return compare(a, b)
|
||||
}
|
||||
63
test/codegen/ifaces.go
Normal file
63
test/codegen/ifaces.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2022 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
|
||||
|
||||
type I interface{ M() }
|
||||
|
||||
func NopConvertIface(x I) I {
|
||||
// amd64:-`.*runtime.convI2I`
|
||||
return I(x)
|
||||
}
|
||||
|
||||
func NopConvertGeneric[T any](x T) T {
|
||||
// amd64:-`.*runtime.convI2I`
|
||||
return T(x)
|
||||
}
|
||||
|
||||
var NopConvertGenericIface = NopConvertGeneric[I]
|
||||
|
||||
func ConvToM(x any) I {
|
||||
// amd64:`CALL runtime.typeAssert`,`MOVL 16\(.*\)`,`MOVQ 8\(.*\)(.*\*1)`
|
||||
// arm64:`CALL runtime.typeAssert`,`LDAR`,`MOVWU`,`MOVD \(R.*\)\(R.*\)`
|
||||
return x.(I)
|
||||
}
|
||||
|
||||
func e1(x any, y *int) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET EQ`
|
||||
return x == y
|
||||
}
|
||||
|
||||
func e2(x any, y *int) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET EQ`
|
||||
return y == x
|
||||
}
|
||||
|
||||
type E *int
|
||||
|
||||
func e3(x any, y E) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET EQ`
|
||||
return x == y
|
||||
}
|
||||
|
||||
type T int
|
||||
|
||||
func (t *T) M() {}
|
||||
|
||||
func i1(x I, y *T) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET EQ`
|
||||
return x == y
|
||||
}
|
||||
|
||||
func i2(x I, y *T) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET EQ`
|
||||
return y == x
|
||||
}
|
||||
535
test/codegen/issue22703.go
Normal file
535
test/codegen/issue22703.go
Normal file
@@ -0,0 +1,535 @@
|
||||
// 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
|
||||
|
||||
type I interface {
|
||||
foo000()
|
||||
foo001()
|
||||
foo002()
|
||||
foo003()
|
||||
foo004()
|
||||
foo005()
|
||||
foo006()
|
||||
foo007()
|
||||
foo008()
|
||||
foo009()
|
||||
foo010()
|
||||
foo011()
|
||||
foo012()
|
||||
foo013()
|
||||
foo014()
|
||||
foo015()
|
||||
foo016()
|
||||
foo017()
|
||||
foo018()
|
||||
foo019()
|
||||
foo020()
|
||||
foo021()
|
||||
foo022()
|
||||
foo023()
|
||||
foo024()
|
||||
foo025()
|
||||
foo026()
|
||||
foo027()
|
||||
foo028()
|
||||
foo029()
|
||||
foo030()
|
||||
foo031()
|
||||
foo032()
|
||||
foo033()
|
||||
foo034()
|
||||
foo035()
|
||||
foo036()
|
||||
foo037()
|
||||
foo038()
|
||||
foo039()
|
||||
foo040()
|
||||
foo041()
|
||||
foo042()
|
||||
foo043()
|
||||
foo044()
|
||||
foo045()
|
||||
foo046()
|
||||
foo047()
|
||||
foo048()
|
||||
foo049()
|
||||
foo050()
|
||||
foo051()
|
||||
foo052()
|
||||
foo053()
|
||||
foo054()
|
||||
foo055()
|
||||
foo056()
|
||||
foo057()
|
||||
foo058()
|
||||
foo059()
|
||||
foo060()
|
||||
foo061()
|
||||
foo062()
|
||||
foo063()
|
||||
foo064()
|
||||
foo065()
|
||||
foo066()
|
||||
foo067()
|
||||
foo068()
|
||||
foo069()
|
||||
foo070()
|
||||
foo071()
|
||||
foo072()
|
||||
foo073()
|
||||
foo074()
|
||||
foo075()
|
||||
foo076()
|
||||
foo077()
|
||||
foo078()
|
||||
foo079()
|
||||
foo080()
|
||||
foo081()
|
||||
foo082()
|
||||
foo083()
|
||||
foo084()
|
||||
foo085()
|
||||
foo086()
|
||||
foo087()
|
||||
foo088()
|
||||
foo089()
|
||||
foo090()
|
||||
foo091()
|
||||
foo092()
|
||||
foo093()
|
||||
foo094()
|
||||
foo095()
|
||||
foo096()
|
||||
foo097()
|
||||
foo098()
|
||||
foo099()
|
||||
foo100()
|
||||
foo101()
|
||||
foo102()
|
||||
foo103()
|
||||
foo104()
|
||||
foo105()
|
||||
foo106()
|
||||
foo107()
|
||||
foo108()
|
||||
foo109()
|
||||
foo110()
|
||||
foo111()
|
||||
foo112()
|
||||
foo113()
|
||||
foo114()
|
||||
foo115()
|
||||
foo116()
|
||||
foo117()
|
||||
foo118()
|
||||
foo119()
|
||||
foo120()
|
||||
foo121()
|
||||
foo122()
|
||||
foo123()
|
||||
foo124()
|
||||
foo125()
|
||||
foo126()
|
||||
foo127()
|
||||
foo128()
|
||||
foo129()
|
||||
foo130()
|
||||
foo131()
|
||||
foo132()
|
||||
foo133()
|
||||
foo134()
|
||||
foo135()
|
||||
foo136()
|
||||
foo137()
|
||||
foo138()
|
||||
foo139()
|
||||
foo140()
|
||||
foo141()
|
||||
foo142()
|
||||
foo143()
|
||||
foo144()
|
||||
foo145()
|
||||
foo146()
|
||||
foo147()
|
||||
foo148()
|
||||
foo149()
|
||||
foo150()
|
||||
foo151()
|
||||
foo152()
|
||||
foo153()
|
||||
foo154()
|
||||
foo155()
|
||||
foo156()
|
||||
foo157()
|
||||
foo158()
|
||||
foo159()
|
||||
foo160()
|
||||
foo161()
|
||||
foo162()
|
||||
foo163()
|
||||
foo164()
|
||||
foo165()
|
||||
foo166()
|
||||
foo167()
|
||||
foo168()
|
||||
foo169()
|
||||
foo170()
|
||||
foo171()
|
||||
foo172()
|
||||
foo173()
|
||||
foo174()
|
||||
foo175()
|
||||
foo176()
|
||||
foo177()
|
||||
foo178()
|
||||
foo179()
|
||||
foo180()
|
||||
foo181()
|
||||
foo182()
|
||||
foo183()
|
||||
foo184()
|
||||
foo185()
|
||||
foo186()
|
||||
foo187()
|
||||
foo188()
|
||||
foo189()
|
||||
foo190()
|
||||
foo191()
|
||||
foo192()
|
||||
foo193()
|
||||
foo194()
|
||||
foo195()
|
||||
foo196()
|
||||
foo197()
|
||||
foo198()
|
||||
foo199()
|
||||
foo200()
|
||||
foo201()
|
||||
foo202()
|
||||
foo203()
|
||||
foo204()
|
||||
foo205()
|
||||
foo206()
|
||||
foo207()
|
||||
foo208()
|
||||
foo209()
|
||||
foo210()
|
||||
foo211()
|
||||
foo212()
|
||||
foo213()
|
||||
foo214()
|
||||
foo215()
|
||||
foo216()
|
||||
foo217()
|
||||
foo218()
|
||||
foo219()
|
||||
foo220()
|
||||
foo221()
|
||||
foo222()
|
||||
foo223()
|
||||
foo224()
|
||||
foo225()
|
||||
foo226()
|
||||
foo227()
|
||||
foo228()
|
||||
foo229()
|
||||
foo230()
|
||||
foo231()
|
||||
foo232()
|
||||
foo233()
|
||||
foo234()
|
||||
foo235()
|
||||
foo236()
|
||||
foo237()
|
||||
foo238()
|
||||
foo239()
|
||||
foo240()
|
||||
foo241()
|
||||
foo242()
|
||||
foo243()
|
||||
foo244()
|
||||
foo245()
|
||||
foo246()
|
||||
foo247()
|
||||
foo248()
|
||||
foo249()
|
||||
foo250()
|
||||
foo251()
|
||||
foo252()
|
||||
foo253()
|
||||
foo254()
|
||||
foo255()
|
||||
foo256()
|
||||
foo257()
|
||||
foo258()
|
||||
foo259()
|
||||
foo260()
|
||||
foo261()
|
||||
foo262()
|
||||
foo263()
|
||||
foo264()
|
||||
foo265()
|
||||
foo266()
|
||||
foo267()
|
||||
foo268()
|
||||
foo269()
|
||||
foo270()
|
||||
foo271()
|
||||
foo272()
|
||||
foo273()
|
||||
foo274()
|
||||
foo275()
|
||||
foo276()
|
||||
foo277()
|
||||
foo278()
|
||||
foo279()
|
||||
foo280()
|
||||
foo281()
|
||||
foo282()
|
||||
foo283()
|
||||
foo284()
|
||||
foo285()
|
||||
foo286()
|
||||
foo287()
|
||||
foo288()
|
||||
foo289()
|
||||
foo290()
|
||||
foo291()
|
||||
foo292()
|
||||
foo293()
|
||||
foo294()
|
||||
foo295()
|
||||
foo296()
|
||||
foo297()
|
||||
foo298()
|
||||
foo299()
|
||||
foo300()
|
||||
foo301()
|
||||
foo302()
|
||||
foo303()
|
||||
foo304()
|
||||
foo305()
|
||||
foo306()
|
||||
foo307()
|
||||
foo308()
|
||||
foo309()
|
||||
foo310()
|
||||
foo311()
|
||||
foo312()
|
||||
foo313()
|
||||
foo314()
|
||||
foo315()
|
||||
foo316()
|
||||
foo317()
|
||||
foo318()
|
||||
foo319()
|
||||
foo320()
|
||||
foo321()
|
||||
foo322()
|
||||
foo323()
|
||||
foo324()
|
||||
foo325()
|
||||
foo326()
|
||||
foo327()
|
||||
foo328()
|
||||
foo329()
|
||||
foo330()
|
||||
foo331()
|
||||
foo332()
|
||||
foo333()
|
||||
foo334()
|
||||
foo335()
|
||||
foo336()
|
||||
foo337()
|
||||
foo338()
|
||||
foo339()
|
||||
foo340()
|
||||
foo341()
|
||||
foo342()
|
||||
foo343()
|
||||
foo344()
|
||||
foo345()
|
||||
foo346()
|
||||
foo347()
|
||||
foo348()
|
||||
foo349()
|
||||
foo350()
|
||||
foo351()
|
||||
foo352()
|
||||
foo353()
|
||||
foo354()
|
||||
foo355()
|
||||
foo356()
|
||||
foo357()
|
||||
foo358()
|
||||
foo359()
|
||||
foo360()
|
||||
foo361()
|
||||
foo362()
|
||||
foo363()
|
||||
foo364()
|
||||
foo365()
|
||||
foo366()
|
||||
foo367()
|
||||
foo368()
|
||||
foo369()
|
||||
foo370()
|
||||
foo371()
|
||||
foo372()
|
||||
foo373()
|
||||
foo374()
|
||||
foo375()
|
||||
foo376()
|
||||
foo377()
|
||||
foo378()
|
||||
foo379()
|
||||
foo380()
|
||||
foo381()
|
||||
foo382()
|
||||
foo383()
|
||||
foo384()
|
||||
foo385()
|
||||
foo386()
|
||||
foo387()
|
||||
foo388()
|
||||
foo389()
|
||||
foo390()
|
||||
foo391()
|
||||
foo392()
|
||||
foo393()
|
||||
foo394()
|
||||
foo395()
|
||||
foo396()
|
||||
foo397()
|
||||
foo398()
|
||||
foo399()
|
||||
foo400()
|
||||
foo401()
|
||||
foo402()
|
||||
foo403()
|
||||
foo404()
|
||||
foo405()
|
||||
foo406()
|
||||
foo407()
|
||||
foo408()
|
||||
foo409()
|
||||
foo410()
|
||||
foo411()
|
||||
foo412()
|
||||
foo413()
|
||||
foo414()
|
||||
foo415()
|
||||
foo416()
|
||||
foo417()
|
||||
foo418()
|
||||
foo419()
|
||||
foo420()
|
||||
foo421()
|
||||
foo422()
|
||||
foo423()
|
||||
foo424()
|
||||
foo425()
|
||||
foo426()
|
||||
foo427()
|
||||
foo428()
|
||||
foo429()
|
||||
foo430()
|
||||
foo431()
|
||||
foo432()
|
||||
foo433()
|
||||
foo434()
|
||||
foo435()
|
||||
foo436()
|
||||
foo437()
|
||||
foo438()
|
||||
foo439()
|
||||
foo440()
|
||||
foo441()
|
||||
foo442()
|
||||
foo443()
|
||||
foo444()
|
||||
foo445()
|
||||
foo446()
|
||||
foo447()
|
||||
foo448()
|
||||
foo449()
|
||||
foo450()
|
||||
foo451()
|
||||
foo452()
|
||||
foo453()
|
||||
foo454()
|
||||
foo455()
|
||||
foo456()
|
||||
foo457()
|
||||
foo458()
|
||||
foo459()
|
||||
foo460()
|
||||
foo461()
|
||||
foo462()
|
||||
foo463()
|
||||
foo464()
|
||||
foo465()
|
||||
foo466()
|
||||
foo467()
|
||||
foo468()
|
||||
foo469()
|
||||
foo470()
|
||||
foo471()
|
||||
foo472()
|
||||
foo473()
|
||||
foo474()
|
||||
foo475()
|
||||
foo476()
|
||||
foo477()
|
||||
foo478()
|
||||
foo479()
|
||||
foo480()
|
||||
foo481()
|
||||
foo482()
|
||||
foo483()
|
||||
foo484()
|
||||
foo485()
|
||||
foo486()
|
||||
foo487()
|
||||
foo488()
|
||||
foo489()
|
||||
foo490()
|
||||
foo491()
|
||||
foo492()
|
||||
foo493()
|
||||
foo494()
|
||||
foo495()
|
||||
foo496()
|
||||
foo497()
|
||||
foo498()
|
||||
foo499()
|
||||
foo500()
|
||||
foo501()
|
||||
foo502()
|
||||
foo503()
|
||||
foo504()
|
||||
foo505()
|
||||
foo506()
|
||||
foo507()
|
||||
foo508()
|
||||
foo509()
|
||||
foo510()
|
||||
foo511()
|
||||
}
|
||||
|
||||
// Nil checks before calling interface methods.
|
||||
// We need it only when the offset is large.
|
||||
|
||||
func callMethodSmallOffset(i I) {
|
||||
// amd64:-"TESTB"
|
||||
i.foo001()
|
||||
}
|
||||
|
||||
func callMethodLargeOffset(i I) {
|
||||
// amd64:"TESTB"
|
||||
i.foo511()
|
||||
}
|
||||
22
test/codegen/issue25378.go
Normal file
22
test/codegen/issue25378.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// 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
|
||||
|
||||
var wsp = [256]bool{
|
||||
' ': true,
|
||||
'\t': true,
|
||||
'\n': true,
|
||||
'\r': true,
|
||||
}
|
||||
|
||||
func zeroExtArgByte(ch [2]byte) bool {
|
||||
return wsp[ch[0]] // amd64:-"MOVBLZX ..,.."
|
||||
}
|
||||
|
||||
func zeroExtArgUint16(ch [2]uint16) bool {
|
||||
return wsp[ch[0]] // amd64:-"MOVWLZX ..,.."
|
||||
}
|
||||
22
test/codegen/issue31618.go
Normal file
22
test/codegen/issue31618.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2019 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
|
||||
|
||||
// Make sure we remove both inline marks in the following code.
|
||||
// Both +5 and +6 should map to real instructions, which can
|
||||
// be used as inline marks instead of explicit nops.
|
||||
func f(x int) int {
|
||||
// amd64:-"XCHGL"
|
||||
x = g(x) + 5
|
||||
// amd64:-"XCHGL"
|
||||
x = g(x) + 6
|
||||
return x
|
||||
}
|
||||
|
||||
func g(x int) int {
|
||||
return x >> 3
|
||||
}
|
||||
25
test/codegen/issue33580.go
Normal file
25
test/codegen/issue33580.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Make sure we reuse large constant loads, if we can.
|
||||
// See issue 33580.
|
||||
|
||||
package codegen
|
||||
|
||||
const (
|
||||
A = 7777777777777777
|
||||
B = 8888888888888888
|
||||
)
|
||||
|
||||
func f(x, y uint64) uint64 {
|
||||
p := x & A
|
||||
q := y & A
|
||||
r := x & B
|
||||
// amd64:-"MOVQ.*8888888888888888"
|
||||
s := y & B
|
||||
|
||||
return p * q * r * s
|
||||
}
|
||||
15
test/codegen/issue38554.go
Normal file
15
test/codegen/issue38554.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2020 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.
|
||||
|
||||
// Test that we are zeroing directly instead of
|
||||
// copying a large zero value. Issue 38554.
|
||||
|
||||
package codegen
|
||||
|
||||
func retlarge() [256]byte {
|
||||
// amd64:-"DUFFCOPY"
|
||||
return [256]byte{}
|
||||
}
|
||||
28
test/codegen/issue42610.go
Normal file
28
test/codegen/issue42610.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2020 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.
|
||||
|
||||
// Don't allow 0 masks in shift lowering rules on ppc64x.
|
||||
// See issue 42610.
|
||||
|
||||
package codegen
|
||||
|
||||
func f32(a []int32, i uint32) {
|
||||
g := func(p int32) int32 {
|
||||
i = uint32(p) * (uint32(p) & (i & 1))
|
||||
return 1
|
||||
}
|
||||
// ppc64x: -"RLWNIM"
|
||||
a[0] = g(8) >> 1
|
||||
}
|
||||
|
||||
func f(a []int, i uint) {
|
||||
g := func(p int) int {
|
||||
i = uint(p) * (uint(p) & (i & 1))
|
||||
return 1
|
||||
}
|
||||
// ppc64x: -"RLDIC"
|
||||
a[0] = g(8) >> 1
|
||||
}
|
||||
31
test/codegen/issue48054.go
Normal file
31
test/codegen/issue48054.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2021 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
|
||||
|
||||
func a(n string) bool {
|
||||
// arm64:"CBZ"
|
||||
if len(n) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func a2(n []int) bool {
|
||||
// arm64:"CBZ"
|
||||
if len(n) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func a3(n []int) bool {
|
||||
// amd64:"TESTQ"
|
||||
if len(n) < 1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
53
test/codegen/issue52635.go
Normal file
53
test/codegen/issue52635.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2022 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.
|
||||
|
||||
// Test that optimized range memclr works with pointers to arrays.
|
||||
// The clears get inlined, see https://github.com/golang/go/issues/56997
|
||||
|
||||
package codegen
|
||||
|
||||
type T struct {
|
||||
a *[10]int
|
||||
b [10]int
|
||||
s []int
|
||||
}
|
||||
|
||||
func (t *T) f() {
|
||||
// amd64:-".*runtime.memclrNoHeapPointers"
|
||||
// amd64:`MOVUPS X15,`
|
||||
for i := range t.a {
|
||||
t.a[i] = 0
|
||||
}
|
||||
|
||||
// amd64:-".*runtime.memclrNoHeapPointers"
|
||||
// amd64:`MOVUPS X15,`
|
||||
for i := range *t.a {
|
||||
t.a[i] = 0
|
||||
}
|
||||
|
||||
// amd64:-".*runtime.memclrNoHeapPointers"
|
||||
// amd64:`MOVUPS X15,`
|
||||
for i := range t.a {
|
||||
(*t.a)[i] = 0
|
||||
}
|
||||
|
||||
// amd64:-".*runtime.memclrNoHeapPointers"
|
||||
// amd64:`MOVUPS X15,`
|
||||
for i := range *t.a {
|
||||
(*t.a)[i] = 0
|
||||
}
|
||||
|
||||
// amd64:-".*runtime.memclrNoHeapPointers"
|
||||
// amd64:`MOVUPS X15,`
|
||||
for i := range t.b {
|
||||
t.b[i] = 0
|
||||
}
|
||||
|
||||
// amd64:".*runtime.memclrNoHeapPointers"
|
||||
for i := range t.s {
|
||||
t.s[i] = 0
|
||||
}
|
||||
}
|
||||
59
test/codegen/issue54467.go
Normal file
59
test/codegen/issue54467.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2022 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
|
||||
|
||||
func f1(x *[4]int, y *[4]int) {
|
||||
// amd64:".*memmove"
|
||||
*x = *y
|
||||
}
|
||||
func f2(x *[4]int, y [4]int) {
|
||||
// amd64:-".*memmove"
|
||||
*x = y
|
||||
}
|
||||
func f3(x *[4]int, y *[4]int) {
|
||||
// amd64:-".*memmove"
|
||||
t := *y
|
||||
// amd64:-".*memmove"
|
||||
*x = t
|
||||
}
|
||||
func f4(x *[4]int, y [4]int) {
|
||||
// amd64:-".*memmove"
|
||||
t := y
|
||||
// amd64:-".*memmove"
|
||||
*x = t
|
||||
}
|
||||
|
||||
type T struct {
|
||||
a [4]int
|
||||
}
|
||||
|
||||
func f5(x, y *T) {
|
||||
// amd64:-".*memmove"
|
||||
x.a = y.a
|
||||
}
|
||||
func f6(x *T, y T) {
|
||||
// amd64:-".*memmove"
|
||||
x.a = y.a
|
||||
}
|
||||
func f7(x *T, y *[4]int) {
|
||||
// amd64:-".*memmove"
|
||||
x.a = *y
|
||||
}
|
||||
func f8(x *[4]int, y *T) {
|
||||
// amd64:-".*memmove"
|
||||
*x = y.a
|
||||
}
|
||||
|
||||
func f9(x [][4]int, y [][4]int, i, j int) {
|
||||
// amd64:-".*memmove"
|
||||
x[i] = y[j]
|
||||
}
|
||||
|
||||
func f10() []byte {
|
||||
// amd64:-".*memmove"
|
||||
return []byte("aReasonablyBigTestString")
|
||||
}
|
||||
34
test/codegen/issue56440.go
Normal file
34
test/codegen/issue56440.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2022 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.
|
||||
|
||||
// Check to make sure that we recognize when the length of an append
|
||||
// is constant. We check this by making sure that the constant length
|
||||
// is folded into a load offset.
|
||||
|
||||
package codegen
|
||||
|
||||
func f(x []int) int {
|
||||
s := make([]int, 3)
|
||||
s = append(s, 4, 5)
|
||||
// amd64:`MOVQ 40\(.*\),`
|
||||
return x[len(s)]
|
||||
}
|
||||
|
||||
func g(x []int, p *bool) int {
|
||||
s := make([]int, 3)
|
||||
for {
|
||||
s = s[:3]
|
||||
if cap(s) < 5 {
|
||||
s = make([]int, 3, 5)
|
||||
}
|
||||
s = append(s, 4, 5)
|
||||
if *p {
|
||||
// amd64:`MOVQ 40\(.*\),`
|
||||
return x[len(s)]
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
23
test/codegen/issue58166.go
Normal file
23
test/codegen/issue58166.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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
|
||||
|
||||
func dgemmSerialNotNot(m, n, k int, a []float64, lda int, b []float64, ldb int, c []float64, ldc int, alpha float64) {
|
||||
for i := 0; i < m; i++ {
|
||||
ctmp := c[i*ldc : i*ldc+n]
|
||||
for l, v := range a[i*lda : i*lda+k] {
|
||||
tmp := alpha * v
|
||||
if tmp != 0 {
|
||||
x := b[l*ldb : l*ldb+n]
|
||||
// amd64:"INCQ"
|
||||
for i, v := range x {
|
||||
ctmp[i] += tmp * v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
test/codegen/issue59297.go
Normal file
17
test/codegen/issue59297.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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
|
||||
|
||||
func f(x, y int, p *int) {
|
||||
// amd64:`MOVQ\sAX, BX`
|
||||
h(8, x)
|
||||
*p = y
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func h(a, b int) {
|
||||
}
|
||||
36
test/codegen/issue60324.go
Normal file
36
test/codegen/issue60324.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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
|
||||
|
||||
func main() {
|
||||
// amd64:"LEAQ command-line-arguments\\.main\\.f\\.g\\.h\\.func3"
|
||||
f(1)()
|
||||
|
||||
// amd64:"LEAQ command-line-arguments\\.main\\.g\\.h\\.func2"
|
||||
g(2)()
|
||||
|
||||
// amd64:"LEAQ command-line-arguments\\.main\\.h\\.func1"
|
||||
h(3)()
|
||||
|
||||
// amd64:"LEAQ command-line-arguments\\.main\\.f\\.g\\.h\\.func4"
|
||||
f(4)()
|
||||
}
|
||||
|
||||
func f(x int) func() {
|
||||
// amd64:"LEAQ command-line-arguments\\.f\\.g\\.h\\.func1"
|
||||
return g(x)
|
||||
}
|
||||
|
||||
func g(x int) func() {
|
||||
// amd64:"LEAQ command-line-arguments\\.g\\.h\\.func1"
|
||||
return h(x)
|
||||
}
|
||||
|
||||
func h(x int) func() {
|
||||
// amd64:"LEAQ command-line-arguments\\.h\\.func1"
|
||||
return func() { recover() }
|
||||
}
|
||||
18
test/codegen/issue60673.go
Normal file
18
test/codegen/issue60673.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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
|
||||
|
||||
//go:noinline
|
||||
func f(x int32) {
|
||||
}
|
||||
|
||||
func g(p *int32) {
|
||||
// argument marshaling code should live at line 17, not line 15.
|
||||
x := *p
|
||||
// 386: `MOVL\s[A-Z]+,\s\(SP\)`
|
||||
f(x)
|
||||
}
|
||||
55
test/codegen/issue61356.go
Normal file
55
test/codegen/issue61356.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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.
|
||||
|
||||
// Make sure this code doesn't generate spill/restore.
|
||||
|
||||
package codegen
|
||||
|
||||
func pack20(in *[20]uint64) uint64 {
|
||||
var out uint64
|
||||
out |= 4
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[0] << 4
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[1] << 7
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[2] << 10
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[3] << 13
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[4] << 16
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[5] << 19
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[6] << 22
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[7] << 25
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[8] << 28
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[9] << 31
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[10] << 34
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[11] << 37
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[12] << 40
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[13] << 43
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[14] << 46
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[15] << 49
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[16] << 52
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[17] << 55
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[18] << 58
|
||||
// amd64:-`.*SP.*`
|
||||
out |= in[19] << 61
|
||||
return out
|
||||
}
|
||||
14
test/codegen/issue63332.go
Normal file
14
test/codegen/issue63332.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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
|
||||
|
||||
func issue63332(c chan int) {
|
||||
x := 0
|
||||
// amd64:-`MOVQ`
|
||||
x += 2
|
||||
c <- x
|
||||
}
|
||||
24
test/codegen/issue66585.go
Normal file
24
test/codegen/issue66585.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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
|
||||
|
||||
var x = func() int {
|
||||
n := 0
|
||||
f(&n)
|
||||
return n
|
||||
}()
|
||||
|
||||
func f(p *int) {
|
||||
*p = 1
|
||||
}
|
||||
|
||||
var y = 1
|
||||
|
||||
// z can be static initialized.
|
||||
//
|
||||
// amd64:-"MOVQ"
|
||||
var z = y
|
||||
52
test/codegen/issue68845.go
Normal file
52
test/codegen/issue68845.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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
|
||||
|
||||
type T1 struct {
|
||||
x string
|
||||
}
|
||||
|
||||
func f1() *T1 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T1{}
|
||||
}
|
||||
|
||||
type T2 struct {
|
||||
x, y string
|
||||
}
|
||||
|
||||
func f2() *T2 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T2{}
|
||||
}
|
||||
|
||||
type T3 struct {
|
||||
x complex128
|
||||
}
|
||||
|
||||
func f3() *T3 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T3{}
|
||||
}
|
||||
|
||||
type T4 struct {
|
||||
x []byte
|
||||
}
|
||||
|
||||
func f4() *T4 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T4{}
|
||||
}
|
||||
|
||||
type T5 struct {
|
||||
x any
|
||||
}
|
||||
|
||||
func f5() *T5 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T5{}
|
||||
}
|
||||
13
test/codegen/issue69635.go
Normal file
13
test/codegen/issue69635.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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
|
||||
|
||||
func calc(a uint64) uint64 {
|
||||
v := a >> 20 & 0x7f
|
||||
// amd64: `SHRQ\s\$17, AX$`, `ANDL\s\$1016, AX$`
|
||||
return v << 3
|
||||
}
|
||||
20
test/codegen/issue70409.go
Normal file
20
test/codegen/issue70409.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// asmcheck -gcflags=-d=ssa/check/on
|
||||
|
||||
// Copyright 2024 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
|
||||
|
||||
// amd64:-"MOVQ"
|
||||
func foo(v uint64) (b [8]byte) {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
b[4] = byte(v >> 32)
|
||||
b[5] = byte(v >> 40)
|
||||
b[6] = byte(v >> 48)
|
||||
b[7] = byte(v >> 56)
|
||||
return b
|
||||
}
|
||||
50
test/codegen/issue72832.go
Normal file
50
test/codegen/issue72832.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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
|
||||
|
||||
type tile1 struct {
|
||||
a uint16
|
||||
b uint16
|
||||
c uint32
|
||||
}
|
||||
|
||||
func store_tile1(t *tile1) {
|
||||
// amd64:`MOVQ`
|
||||
t.a, t.b, t.c = 1, 1, 1
|
||||
}
|
||||
|
||||
type tile2 struct {
|
||||
a, b, c, d, e int8
|
||||
}
|
||||
|
||||
func store_tile2(t *tile2) {
|
||||
// amd64:`MOVW`
|
||||
t.a, t.b = 1, 1
|
||||
// amd64:`MOVW`
|
||||
t.d, t.e = 1, 1
|
||||
}
|
||||
|
||||
type tile3 struct {
|
||||
a, b uint8
|
||||
c uint16
|
||||
}
|
||||
|
||||
func store_shifted(t *tile3, x uint32) {
|
||||
// amd64:`MOVL`
|
||||
// ppc64:`MOVHBR`
|
||||
t.a = uint8(x)
|
||||
t.b = uint8(x >> 8)
|
||||
t.c = uint16(x >> 16)
|
||||
}
|
||||
|
||||
func store_const(t *tile3) {
|
||||
// 0x00030201
|
||||
// amd64:`MOVL\s\$197121`
|
||||
// 0x01020003
|
||||
// ppc64:`MOVD\s\$16908291`
|
||||
t.a, t.b, t.c = 1, 2, 3
|
||||
}
|
||||
47
test/codegen/issue74485.go
Normal file
47
test/codegen/issue74485.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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
|
||||
|
||||
func divUint64(b uint64) uint64 {
|
||||
// amd64:"SHRQ [$]63, AX"
|
||||
return b / 9223372036854775808
|
||||
}
|
||||
|
||||
func divUint32(b uint32) uint32 {
|
||||
// amd64:"SHRL [$]31, AX"
|
||||
return b / 2147483648
|
||||
}
|
||||
|
||||
func divUint16(b uint16) uint16 {
|
||||
// amd64:"SHRW [$]15, AX"
|
||||
return b / 32768
|
||||
}
|
||||
|
||||
func divUint8(b uint8) uint8 {
|
||||
// amd64:"SHRB [$]7, AL"
|
||||
return b / 128
|
||||
}
|
||||
|
||||
func modUint64(b uint64) uint64 {
|
||||
// amd64:"BTRQ [$]63, AX"
|
||||
return b % 9223372036854775808
|
||||
}
|
||||
|
||||
func modUint32(b uint32) uint32 {
|
||||
// amd64:"ANDL [$]2147483647, AX"
|
||||
return b % 2147483648
|
||||
}
|
||||
|
||||
func modUint16(b uint16) uint16 {
|
||||
// amd64:"ANDL [$]32767, AX"
|
||||
return b % 32768
|
||||
}
|
||||
|
||||
func modUint8(b uint8) uint8 {
|
||||
// amd64:"ANDL [$]127, AX"
|
||||
return b % 128
|
||||
}
|
||||
17
test/codegen/issue74788.go
Normal file
17
test/codegen/issue74788.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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
|
||||
|
||||
func fa(a [2]int) (r [2]int) {
|
||||
// amd64:1`MOVUPS[^,]+, X[0-9]+$`,1`MOVUPS\sX[0-9]+,[^\n]+$`
|
||||
return a
|
||||
}
|
||||
|
||||
func fb(a [4]int) (r [4]int) {
|
||||
// amd64:2`MOVUPS[^,]+, X[0-9]+$`,2`MOVUPS\sX[0-9]+,[^\n]+$`
|
||||
return a
|
||||
}
|
||||
22
test/codegen/issue75203.go
Normal file
22
test/codegen/issue75203.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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 "reflect"
|
||||
|
||||
func f() reflect.Type {
|
||||
// amd64:`LEAQ\stype:\*int\(SB\)`
|
||||
// arm64:`MOVD\s\$type:\*int\(SB\)`
|
||||
return reflect.TypeFor[*int]()
|
||||
}
|
||||
|
||||
func g() reflect.Type {
|
||||
// amd64:`LEAQ\stype:int\(SB\)`
|
||||
// arm64:`MOVD\s\$type:int\(SB\)`
|
||||
return reflect.TypeFor[int]()
|
||||
}
|
||||
|
||||
24
test/codegen/load_type_from_itab.go
Normal file
24
test/codegen/load_type_from_itab.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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.
|
||||
|
||||
// This test makes sure that we statically load a type from an itab, instead
|
||||
// of doing a indirect load from thet itab.
|
||||
|
||||
package codegen
|
||||
|
||||
type M interface{ M() }
|
||||
type A interface{ A() }
|
||||
|
||||
type Impl struct{}
|
||||
|
||||
func (*Impl) M() {}
|
||||
func (*Impl) A() {}
|
||||
|
||||
func main() {
|
||||
var a M = &Impl{}
|
||||
// amd64:`LEAQ type:.*Impl`
|
||||
a.(A).A()
|
||||
}
|
||||
41
test/codegen/logic.go
Normal file
41
test/codegen/logic.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// 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
|
||||
|
||||
// Test to make sure that (CMPQ (ANDQ x y) [0]) does not get rewritten to
|
||||
// (TESTQ x y) if the ANDQ has other uses. If that rewrite happens, then one
|
||||
// of the args of the ANDQ needs to be saved so it can be used as the arg to TESTQ.
|
||||
func andWithUse(x, y int) int {
|
||||
z := x & y
|
||||
// amd64:`TESTQ\s(AX, AX|BX, BX|CX, CX|DX, DX|SI, SI|DI, DI|R8, R8|R9, R9|R10, R10|R11, R11|R12, R12|R13, R13|R15, R15)`
|
||||
if z == 0 {
|
||||
return 77
|
||||
}
|
||||
// use z by returning it
|
||||
return z
|
||||
}
|
||||
|
||||
// Verify (OR x (NOT y)) rewrites to (ORN x y) where supported
|
||||
func ornot(x, y int) int {
|
||||
// ppc64x:"ORN"
|
||||
z := x | ^y
|
||||
return z
|
||||
}
|
||||
|
||||
// Verify that (OR (NOT x) (NOT y)) rewrites to (NOT (AND x y))
|
||||
func orDemorgans(x, y int) int {
|
||||
// amd64:"AND" -"OR"
|
||||
z := ^x | ^y
|
||||
return z
|
||||
}
|
||||
|
||||
// Verify that (AND (NOT x) (NOT y)) rewrites to (NOT (OR x y))
|
||||
func andDemorgans(x, y int) int {
|
||||
// amd64:"OR" -"AND"
|
||||
z := ^x & ^y
|
||||
return z
|
||||
}
|
||||
484
test/codegen/mapaccess.go
Normal file
484
test/codegen/mapaccess.go
Normal file
@@ -0,0 +1,484 @@
|
||||
// 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
|
||||
|
||||
// These tests check that mapaccess calls are not used.
|
||||
// Issues #23661 and #24364.
|
||||
|
||||
func mapCompoundAssignmentInt8() {
|
||||
m := make(map[int8]int8, 0)
|
||||
var k int8 = 0
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] += 67
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] -= 123
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] *= 45
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] |= 78
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] ^= 89
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] <<= 9
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] >>= 10
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k]++
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k]--
|
||||
}
|
||||
|
||||
func mapCompoundAssignmentInt32() {
|
||||
m := make(map[int32]int32, 0)
|
||||
var k int32 = 0
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] += 67890
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] -= 123
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] *= 456
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] |= 78
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] ^= 89
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] <<= 9
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] >>= 10
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k]++
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k]--
|
||||
}
|
||||
|
||||
func mapCompoundAssignmentInt64() {
|
||||
m := make(map[int64]int64, 0)
|
||||
var k int64 = 0
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] += 67890
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] -= 123
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] *= 456
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] |= 78
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] ^= 89
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] <<= 9
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] >>= 10
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k]++
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k]--
|
||||
}
|
||||
|
||||
func mapCompoundAssignmentComplex128() {
|
||||
m := make(map[complex128]complex128, 0)
|
||||
var k complex128 = 0
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] += 67890
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] -= 123
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] *= 456
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k]++
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k]--
|
||||
}
|
||||
|
||||
func mapCompoundAssignmentString() {
|
||||
m := make(map[string]string, 0)
|
||||
var k string = "key"
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] += "value"
|
||||
}
|
||||
|
||||
var sinkAppend bool
|
||||
|
||||
func mapAppendAssignmentInt8() {
|
||||
m := make(map[int8][]int8, 0)
|
||||
var k int8 = 0
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], 1)
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], 1, 2, 3)
|
||||
|
||||
a := []int8{7, 8, 9, 0}
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], a...)
|
||||
|
||||
// Exceptions
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(a, m[k]...)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
sinkAppend, m[k] = !sinkAppend, append(m[k], 99)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(m[k+1], 100)
|
||||
}
|
||||
|
||||
func mapAppendAssignmentInt32() {
|
||||
m := make(map[int32][]int32, 0)
|
||||
var k int32 = 0
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], 1)
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], 1, 2, 3)
|
||||
|
||||
a := []int32{7, 8, 9, 0}
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], a...)
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k+1] = append(m[k+1], a...)
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[-k] = append(m[-k], a...)
|
||||
|
||||
// Exceptions
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(a, m[k]...)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
sinkAppend, m[k] = !sinkAppend, append(m[k], 99)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(m[k+1], 100)
|
||||
}
|
||||
|
||||
func mapAppendAssignmentInt64() {
|
||||
m := make(map[int64][]int64, 0)
|
||||
var k int64 = 0
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], 1)
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], 1, 2, 3)
|
||||
|
||||
a := []int64{7, 8, 9, 0}
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], a...)
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k+1] = append(m[k+1], a...)
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[-k] = append(m[-k], a...)
|
||||
|
||||
// Exceptions
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(a, m[k]...)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
sinkAppend, m[k] = !sinkAppend, append(m[k], 99)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(m[k+1], 100)
|
||||
}
|
||||
|
||||
func mapAppendAssignmentComplex128() {
|
||||
m := make(map[complex128][]complex128, 0)
|
||||
var k complex128 = 0
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], 1)
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], 1, 2, 3)
|
||||
|
||||
a := []complex128{7, 8, 9, 0}
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], a...)
|
||||
|
||||
// Exceptions
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(a, m[k]...)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
sinkAppend, m[k] = !sinkAppend, append(m[k], 99)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(m[k+1], 100)
|
||||
}
|
||||
|
||||
func mapAppendAssignmentString() {
|
||||
m := make(map[string][]string, 0)
|
||||
var k string = "key"
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], "1")
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], "1", "2", "3")
|
||||
|
||||
a := []string{"7", "8", "9", "0"}
|
||||
|
||||
// 386:-".*mapaccess"
|
||||
// amd64:-".*mapaccess"
|
||||
// arm:-".*mapaccess"
|
||||
// arm64:-".*mapaccess"
|
||||
m[k] = append(m[k], a...)
|
||||
|
||||
// Exceptions
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(a, m[k]...)
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
sinkAppend, m[k] = !sinkAppend, append(m[k], "99")
|
||||
|
||||
// 386:".*mapaccess"
|
||||
// amd64:".*mapaccess"
|
||||
// arm:".*mapaccess"
|
||||
// arm64:".*mapaccess"
|
||||
m[k] = append(m[k+"1"], "100")
|
||||
}
|
||||
245
test/codegen/maps.go
Normal file
245
test/codegen/maps.go
Normal file
@@ -0,0 +1,245 @@
|
||||
// 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
|
||||
|
||||
// This file contains code generation tests related to the handling of
|
||||
// map types.
|
||||
|
||||
// ------------------- //
|
||||
// Access Const //
|
||||
// ------------------- //
|
||||
|
||||
// Direct use of constants in fast map access calls (Issue #19015).
|
||||
|
||||
func AccessInt1(m map[int]int) int {
|
||||
// amd64:"MOV[LQ] [$]5"
|
||||
return m[5]
|
||||
}
|
||||
|
||||
func AccessInt2(m map[int]int) bool {
|
||||
// amd64:"MOV[LQ] [$]5"
|
||||
_, ok := m[5]
|
||||
return ok
|
||||
}
|
||||
|
||||
func AccessString1(m map[string]int) int {
|
||||
// amd64:`.*"abc"`
|
||||
return m["abc"]
|
||||
}
|
||||
|
||||
func AccessString2(m map[string]int) bool {
|
||||
// amd64:`.*"abc"`
|
||||
_, ok := m["abc"]
|
||||
return ok
|
||||
}
|
||||
|
||||
func AccessStringIntArray2(m map[string][16]int, k string) bool {
|
||||
// amd64:-"MOVUPS"
|
||||
_, ok := m[k]
|
||||
return ok
|
||||
}
|
||||
|
||||
type Struct struct {
|
||||
A, B, C, D, E, F, G, H, I, J int
|
||||
}
|
||||
|
||||
func AccessStringStruct2(m map[string]Struct, k string) bool {
|
||||
// amd64:-"MOVUPS"
|
||||
_, ok := m[k]
|
||||
return ok
|
||||
}
|
||||
|
||||
func AccessIntArrayLarge2(m map[int][512]int, k int) bool {
|
||||
// amd64:-"REP",-"MOVSQ"
|
||||
_, ok := m[k]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ------------------- //
|
||||
// String Conversion //
|
||||
// ------------------- //
|
||||
|
||||
func LookupStringConversionSimple(m map[string]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
return m[string(bytes)]
|
||||
}
|
||||
|
||||
func LookupStringConversionStructLit(m map[struct{ string }]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
return m[struct{ string }{string(bytes)}]
|
||||
}
|
||||
|
||||
func LookupStringConversionArrayLit(m map[[2]string]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
return m[[2]string{string(bytes), string(bytes)}]
|
||||
}
|
||||
|
||||
func LookupStringConversionNestedLit(m map[[1]struct{ s [1]string }]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
return m[[1]struct{ s [1]string }{struct{ s [1]string }{s: [1]string{string(bytes)}}}]
|
||||
}
|
||||
|
||||
func LookupStringConversionKeyedArrayLit(m map[[2]string]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
return m[[2]string{0: string(bytes)}]
|
||||
}
|
||||
|
||||
func LookupStringConversion1(m map[string]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
s := string(bytes)
|
||||
return m[s]
|
||||
}
|
||||
func LookupStringConversion2(m *map[string]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
s := string(bytes)
|
||||
return (*m)[s]
|
||||
}
|
||||
func LookupStringConversion3(m map[string]int, bytes []byte) (int, bool) {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
s := string(bytes)
|
||||
r, ok := m[s]
|
||||
return r, ok
|
||||
}
|
||||
func DeleteStringConversion(m map[string]int, bytes []byte) {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
s := string(bytes)
|
||||
delete(m, s)
|
||||
}
|
||||
|
||||
// ------------------- //
|
||||
// Map Clear //
|
||||
// ------------------- //
|
||||
|
||||
// Optimization of map clear idiom (Issue #20138).
|
||||
|
||||
func MapClearReflexive(m map[int]int) {
|
||||
// amd64:`.*runtime\.mapclear`
|
||||
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
|
||||
func MapClearIndirect(m map[int]int) {
|
||||
s := struct{ m map[int]int }{m: m}
|
||||
// amd64:`.*runtime\.mapclear`
|
||||
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
for k := range s.m {
|
||||
delete(s.m, k)
|
||||
}
|
||||
}
|
||||
|
||||
func MapClearPointer(m map[*byte]int) {
|
||||
// amd64:`.*runtime\.mapclear`
|
||||
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
|
||||
func MapClearNotReflexive(m map[float64]int) {
|
||||
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
// amd64:-`.*runtime\.mapclear`
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
|
||||
func MapClearInterface(m map[interface{}]int) {
|
||||
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
// amd64:-`.*runtime\.mapclear`
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
|
||||
func MapClearSideEffect(m map[int]int) int {
|
||||
k := 0
|
||||
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
// amd64:-`.*runtime\.mapclear`
|
||||
for k = range m {
|
||||
delete(m, k)
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func MapLiteralSizing(x int) (map[int]int, map[int]int) {
|
||||
// This is tested for internal/abi/maps.go:MapBucketCountBits={3,4,5}
|
||||
// amd64:"MOVL [$]33,"
|
||||
m := map[int]int{
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3,
|
||||
4: 4,
|
||||
5: 5,
|
||||
6: 6,
|
||||
7: 7,
|
||||
8: 8,
|
||||
9: 9,
|
||||
10: 10,
|
||||
11: 11,
|
||||
12: 12,
|
||||
13: 13,
|
||||
14: 14,
|
||||
15: 15,
|
||||
16: 16,
|
||||
17: 17,
|
||||
18: 18,
|
||||
19: 19,
|
||||
20: 20,
|
||||
21: 21,
|
||||
22: 22,
|
||||
23: 23,
|
||||
24: 24,
|
||||
25: 25,
|
||||
26: 26,
|
||||
27: 27,
|
||||
28: 28,
|
||||
29: 29,
|
||||
30: 30,
|
||||
31: 32,
|
||||
32: 32,
|
||||
}
|
||||
// amd64:"MOVL [$]33,"
|
||||
n := map[int]int{
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3,
|
||||
4: 4,
|
||||
5: 5,
|
||||
6: 6,
|
||||
7: 7,
|
||||
8: 8,
|
||||
9: 9,
|
||||
10: 10,
|
||||
11: 11,
|
||||
12: 12,
|
||||
13: 13,
|
||||
14: 14,
|
||||
15: 15,
|
||||
16: 16,
|
||||
17: 17,
|
||||
18: 18,
|
||||
19: 19,
|
||||
20: 20,
|
||||
21: 21,
|
||||
22: 22,
|
||||
23: 23,
|
||||
24: 24,
|
||||
25: 25,
|
||||
26: 26,
|
||||
27: 27,
|
||||
28: 28,
|
||||
29: 29,
|
||||
30: 30,
|
||||
31: 32,
|
||||
32: 32,
|
||||
}
|
||||
return m, n
|
||||
}
|
||||
377
test/codegen/math.go
Normal file
377
test/codegen/math.go
Normal file
@@ -0,0 +1,377 @@
|
||||
// asmcheck -gcflags=-d=converthash=qy
|
||||
|
||||
// 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 "math"
|
||||
|
||||
var sink64 [8]float64
|
||||
|
||||
func approx(x float64) {
|
||||
// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
|
||||
// amd64:"ROUNDSD [$]2"
|
||||
// s390x:"FIDBR [$]6"
|
||||
// arm64:"FRINTPD"
|
||||
// ppc64x:"FRIP"
|
||||
// wasm:"F64Ceil"
|
||||
sink64[0] = math.Ceil(x)
|
||||
|
||||
// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
|
||||
// amd64:"ROUNDSD [$]1"
|
||||
// s390x:"FIDBR [$]7"
|
||||
// arm64:"FRINTMD"
|
||||
// ppc64x:"FRIM"
|
||||
// wasm:"F64Floor"
|
||||
sink64[1] = math.Floor(x)
|
||||
|
||||
// s390x:"FIDBR [$]1"
|
||||
// arm64:"FRINTAD"
|
||||
// ppc64x:"FRIN"
|
||||
sink64[2] = math.Round(x)
|
||||
|
||||
// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
|
||||
// amd64:"ROUNDSD [$]3"
|
||||
// s390x:"FIDBR [$]5"
|
||||
// arm64:"FRINTZD"
|
||||
// ppc64x:"FRIZ"
|
||||
// wasm:"F64Trunc"
|
||||
sink64[3] = math.Trunc(x)
|
||||
|
||||
// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
|
||||
// amd64:"ROUNDSD [$]0"
|
||||
// s390x:"FIDBR [$]4"
|
||||
// arm64:"FRINTND"
|
||||
// wasm:"F64Nearest"
|
||||
sink64[4] = math.RoundToEven(x)
|
||||
}
|
||||
|
||||
func sqrt(x float64) float64 {
|
||||
// amd64:"SQRTSD"
|
||||
// 386/sse2:"SQRTSD" 386/softfloat:-"SQRTD"
|
||||
// arm64:"FSQRTD"
|
||||
// arm/7:"SQRTD"
|
||||
// loong64:"SQRTD"
|
||||
// mips/hardfloat:"SQRTD" mips/softfloat:-"SQRTD"
|
||||
// mips64/hardfloat:"SQRTD" mips64/softfloat:-"SQRTD"
|
||||
// wasm:"F64Sqrt"
|
||||
// ppc64x:"FSQRT"
|
||||
// riscv64: "FSQRTD"
|
||||
return math.Sqrt(x)
|
||||
}
|
||||
|
||||
func sqrt32(x float32) float32 {
|
||||
// amd64:"SQRTSS"
|
||||
// 386/sse2:"SQRTSS" 386/softfloat:-"SQRTS"
|
||||
// arm64:"FSQRTS"
|
||||
// arm/7:"SQRTF"
|
||||
// loong64:"SQRTF"
|
||||
// mips/hardfloat:"SQRTF" mips/softfloat:-"SQRTF"
|
||||
// mips64/hardfloat:"SQRTF" mips64/softfloat:-"SQRTF"
|
||||
// wasm:"F32Sqrt"
|
||||
// ppc64x:"FSQRTS"
|
||||
// riscv64: "FSQRTS"
|
||||
return float32(math.Sqrt(float64(x)))
|
||||
}
|
||||
|
||||
// Check that it's using integer registers
|
||||
func abs(x, y float64) {
|
||||
// amd64:"BTRQ [$]63"
|
||||
// arm64:"FABSD "
|
||||
// loong64:"ABSD "
|
||||
// s390x:"LPDFR " -"MOVD " (no integer load/store)
|
||||
// ppc64x:"FABS "
|
||||
// riscv64:"FABSD "
|
||||
// wasm:"F64Abs"
|
||||
// arm/6:"ABSD "
|
||||
// mips64/hardfloat:"ABSD "
|
||||
// mips/hardfloat:"ABSD "
|
||||
sink64[0] = math.Abs(x)
|
||||
|
||||
// amd64:"BTRQ [$]63" "PXOR" (TODO: this should be BTSQ)
|
||||
// s390x:"LNDFR " -"MOVD " (no integer load/store)
|
||||
// ppc64x:"FNABS "
|
||||
sink64[1] = -math.Abs(y)
|
||||
}
|
||||
|
||||
// Check that it's using integer registers
|
||||
func abs32(x float32) float32 {
|
||||
// s390x:"LPDFR" -"LDEBR" -"LEDBR" (no float64 conversion)
|
||||
return float32(math.Abs(float64(x)))
|
||||
}
|
||||
|
||||
// Check that it's using integer registers
|
||||
func copysign(a, b, c float64) {
|
||||
// amd64:"BTRQ [$]63" "ANDQ" "ORQ"
|
||||
// loong64:"FCOPYSGD"
|
||||
// s390x:"CPSDR" -"MOVD" (no integer load/store)
|
||||
// ppc64x:"FCPSGN"
|
||||
// riscv64:"FSGNJD"
|
||||
// wasm:"F64Copysign"
|
||||
sink64[0] = math.Copysign(a, b)
|
||||
|
||||
// amd64:"BTSQ [$]63"
|
||||
// loong64:"FCOPYSGD"
|
||||
// s390x:"LNDFR " -"MOVD " (no integer load/store)
|
||||
// ppc64x:"FCPSGN"
|
||||
// riscv64:"FSGNJD"
|
||||
// arm64:"ORR", -"AND"
|
||||
sink64[1] = math.Copysign(c, -1)
|
||||
|
||||
// Like math.Copysign(c, -1), but with integer operations. Useful
|
||||
// for platforms that have a copysign opcode to see if it's detected.
|
||||
// s390x:"LNDFR " -"MOVD " (no integer load/store)
|
||||
sink64[2] = math.Float64frombits(math.Float64bits(a) | 1<<63)
|
||||
|
||||
// amd64:"ANDQ" "ORQ"
|
||||
// loong64:"FCOPYSGD"
|
||||
// s390x:"CPSDR " -"MOVD " (no integer load/store)
|
||||
// ppc64x:"FCPSGN"
|
||||
// riscv64:"FSGNJD"
|
||||
sink64[3] = math.Copysign(-1, c)
|
||||
}
|
||||
|
||||
func fma(x, y, z float64) float64 {
|
||||
// amd64/v3:-".*x86HasFMA"
|
||||
// amd64:"VFMADD231SD"
|
||||
// arm/6:"FMULAD"
|
||||
// arm64:"FMADDD"
|
||||
// loong64:"FMADDD"
|
||||
// s390x:"FMADD"
|
||||
// ppc64x:"FMADD"
|
||||
// riscv64:"FMADDD"
|
||||
return math.FMA(x, y, z)
|
||||
}
|
||||
|
||||
func fms(x, y, z float64) float64 {
|
||||
// riscv64:"FMSUBD"
|
||||
return math.FMA(x, y, -z)
|
||||
}
|
||||
|
||||
func fnms(x, y, z float64) float64 {
|
||||
// riscv64:"FNMSUBD" -"FNMADDD"
|
||||
return math.FMA(-x, y, z)
|
||||
}
|
||||
|
||||
func fnma(x, y, z float64) float64 {
|
||||
// riscv64:"FNMADDD" -"FNMSUBD"
|
||||
return math.FMA(x, -y, -z)
|
||||
}
|
||||
|
||||
func isPosInf(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return math.IsInf(x, 1)
|
||||
}
|
||||
|
||||
func isPosInfEq(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x == math.Inf(1)
|
||||
}
|
||||
|
||||
func isPosInfCmp(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x > math.MaxFloat64
|
||||
}
|
||||
|
||||
func isNotPosInf(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return !math.IsInf(x, 1)
|
||||
}
|
||||
|
||||
func isNotPosInfEq(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x != math.Inf(1)
|
||||
}
|
||||
|
||||
func isNotPosInfCmp(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x <= math.MaxFloat64
|
||||
}
|
||||
|
||||
func isNegInf(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return math.IsInf(x, -1)
|
||||
}
|
||||
|
||||
func isNegInfEq(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x == math.Inf(-1)
|
||||
}
|
||||
|
||||
func isNegInfCmp(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x < -math.MaxFloat64
|
||||
}
|
||||
|
||||
func isNotNegInf(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return !math.IsInf(x, -1)
|
||||
}
|
||||
|
||||
func isNotNegInfEq(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x != math.Inf(-1)
|
||||
}
|
||||
|
||||
func isNotNegInfCmp(x float64) bool {
|
||||
// riscv64:"FCLASSD"
|
||||
return x >= -math.MaxFloat64
|
||||
}
|
||||
|
||||
func fromFloat64(f64 float64) uint64 {
|
||||
// amd64:"MOVQ X.*, [^X].*"
|
||||
// arm64:"FMOVD F.*, R.*"
|
||||
// loong64:"MOVV F.*, R.*"
|
||||
// ppc64x:"MFVSRD"
|
||||
// mips64/hardfloat:"MOVV F.*, R.*"
|
||||
// riscv64:"FMVXD"
|
||||
return math.Float64bits(f64+1) + 1
|
||||
}
|
||||
|
||||
func fromFloat32(f32 float32) uint32 {
|
||||
// amd64:"MOVL X.*, [^X].*"
|
||||
// arm64:"FMOVS F.*, R.*"
|
||||
// loong64:"MOVW F.*, R.*"
|
||||
// mips64/hardfloat:"MOVW F.*, R.*"
|
||||
// riscv64:"FMVXW"
|
||||
return math.Float32bits(f32+1) + 1
|
||||
}
|
||||
|
||||
func toFloat64(u64 uint64) float64 {
|
||||
// amd64:"MOVQ [^X].*, X.*"
|
||||
// arm64:"FMOVD R.*, F.*"
|
||||
// loong64:"MOVV R.*, F.*"
|
||||
// ppc64x:"MTVSRD"
|
||||
// mips64/hardfloat:"MOVV R.*, F.*"
|
||||
// riscv64:"FMVDX"
|
||||
return math.Float64frombits(u64+1) + 1
|
||||
}
|
||||
|
||||
func toFloat32(u32 uint32) float32 {
|
||||
// amd64:"MOVL [^X].*, X.*"
|
||||
// arm64:"FMOVS R.*, F.*"
|
||||
// loong64:"MOVW R.*, F.*"
|
||||
// mips64/hardfloat:"MOVW R.*, F.*"
|
||||
// riscv64:"FMVWX"
|
||||
return math.Float32frombits(u32+1) + 1
|
||||
}
|
||||
|
||||
// Test that comparisons with constants converted to float
|
||||
// are evaluated at compile-time
|
||||
|
||||
func constantCheck64() bool {
|
||||
// amd64:"(MOVB [$]0)|(XORL [A-Z][A-Z0-9]+, [A-Z][A-Z0-9]+)" -"FCMP" -"MOVB [$]1"
|
||||
// s390x:"MOV(B|BZ|D) [$]0," -"FCMPU" -"MOV(B|BZ|D) [$]1,"
|
||||
return 0.5 == float64(uint32(1)) || 1.5 > float64(uint64(1<<63))
|
||||
}
|
||||
|
||||
func constantCheck32() bool {
|
||||
// amd64:"MOV(B|L) [$]1" -"FCMP" -"MOV(B|L) [$]0"
|
||||
// s390x:"MOV(B|BZ|D) [$]1," -"FCMPU" -"MOV(B|BZ|D) [$]0,"
|
||||
return float32(0.5) <= float32(int64(1)) && float32(1.5) >= float32(int32(-1<<31))
|
||||
}
|
||||
|
||||
// Test that integer constants are converted to floating point constants
|
||||
// at compile-time
|
||||
|
||||
func constantConvert32(x float32) float32 {
|
||||
// amd64:"MOVSS [$]f32.3f800000\\(SB\\)"
|
||||
// s390x:"FMOVS [$]f32.3f800000\\(SB\\)"
|
||||
// ppc64x/power8:"FMOVS [$]f32.3f800000\\(SB\\)"
|
||||
// ppc64x/power9:"FMOVS [$]f32.3f800000\\(SB\\)"
|
||||
// ppc64x/power10:"XXSPLTIDP [$]1065353216, VS0"
|
||||
// arm64:"FMOVS [$]\\(1.0\\)"
|
||||
if x > math.Float32frombits(0x3f800000) {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func constantConvertInt32(x uint32) uint32 {
|
||||
// amd64:-"MOVSS"
|
||||
// s390x:-"FMOVS"
|
||||
// ppc64x:-"FMOVS"
|
||||
// arm64:-"FMOVS"
|
||||
if x > math.Float32bits(1) {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func nanGenerate64() float64 {
|
||||
// Test to make sure we don't generate a NaN while constant propagating.
|
||||
// See issue 36400.
|
||||
zero := 0.0
|
||||
// amd64:-"DIVSD"
|
||||
inf := 1 / zero // +inf. We can constant propagate this one.
|
||||
negone := -1.0
|
||||
|
||||
// amd64:"DIVSD"
|
||||
z0 := zero / zero
|
||||
// amd64/v1,amd64/v2:"MULSD"
|
||||
z1 := zero * inf
|
||||
// amd64:"SQRTSD"
|
||||
z2 := math.Sqrt(negone)
|
||||
// amd64/v3:"VFMADD231SD"
|
||||
return z0 + z1 + z2
|
||||
}
|
||||
|
||||
func nanGenerate32() float32 {
|
||||
zero := float32(0.0)
|
||||
// amd64:-"DIVSS"
|
||||
inf := 1 / zero // +inf. We can constant propagate this one.
|
||||
|
||||
// amd64:"DIVSS"
|
||||
z0 := zero / zero
|
||||
// amd64/v1,amd64/v2:"MULSS"
|
||||
z1 := zero * inf
|
||||
// amd64/v3:"VFMADD231SS"
|
||||
return z0 + z1
|
||||
}
|
||||
|
||||
func outOfBoundsConv(i32 *[2]int32, u32 *[2]uint32, i64 *[2]int64, u64 *[2]uint64) {
|
||||
// arm64: "FCVTZSDW"
|
||||
// amd64: "CVTTSD2SL", "CVTSD2SS"
|
||||
i32[0] = int32(two40())
|
||||
// arm64: "FCVTZSDW"
|
||||
// amd64: "CVTTSD2SL", "CVTSD2SS"
|
||||
i32[1] = int32(-two40())
|
||||
// arm64: "FCVTZSDW"
|
||||
// amd64: "CVTTSD2SL", "CVTSD2SS"
|
||||
u32[0] = uint32(two41())
|
||||
// on arm64, this uses an explicit <0 comparison, so it constant folds.
|
||||
// on amd64, this uses an explicit <0 comparison, so it constant folds.
|
||||
// amd64: "MOVL [$]0,"
|
||||
u32[1] = uint32(minus1())
|
||||
// arm64: "FCVTZSD"
|
||||
// amd64: "CVTTSD2SQ"
|
||||
i64[0] = int64(two80())
|
||||
// arm64: "FCVTZSD"
|
||||
// amd64: "CVTTSD2SQ"
|
||||
i64[1] = int64(-two80())
|
||||
// arm64: "FCVTZUD"
|
||||
// amd64: "CVTTSD2SQ"
|
||||
u64[0] = uint64(two81())
|
||||
// arm64: "FCVTZUD"
|
||||
// on amd64, this uses an explicit <0 comparison, so it constant folds.
|
||||
// amd64: "MOVQ [$]0,"
|
||||
u64[1] = uint64(minus1())
|
||||
}
|
||||
|
||||
func two40() float64 {
|
||||
return 1 << 40
|
||||
}
|
||||
func two41() float64 {
|
||||
return 1 << 41
|
||||
}
|
||||
func two80() float64 {
|
||||
return 1 << 80
|
||||
}
|
||||
func two81() float64 {
|
||||
return 1 << 81
|
||||
}
|
||||
func minus1() float64 {
|
||||
return -1
|
||||
}
|
||||
1011
test/codegen/mathbits.go
Normal file
1011
test/codegen/mathbits.go
Normal file
File diff suppressed because it is too large
Load Diff
1089
test/codegen/memcombine.go
Normal file
1089
test/codegen/memcombine.go
Normal file
File diff suppressed because it is too large
Load Diff
17
test/codegen/memcse.go
Normal file
17
test/codegen/memcse.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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.
|
||||
|
||||
// Test common subexpression elimination of loads around other operations.
|
||||
|
||||
package codegen
|
||||
|
||||
func loadsAroundMemEqual(p *int, s1, s2 string) (int, bool) {
|
||||
x := *p
|
||||
eq := s1 == s2
|
||||
y := *p
|
||||
// arm64:"MOVD ZR, R0"
|
||||
return x - y, eq
|
||||
}
|
||||
403
test/codegen/memops.go
Normal file
403
test/codegen/memops.go
Normal file
@@ -0,0 +1,403 @@
|
||||
// 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
|
||||
|
||||
var x [2]bool
|
||||
var x8 [2]uint8
|
||||
var x16 [2]uint16
|
||||
var x32 [2]uint32
|
||||
var x64 [2]uint64
|
||||
|
||||
func compMem1() int {
|
||||
// amd64:`CMPB command-line-arguments.x\+1\(SB\), [$]0`
|
||||
if x[1] {
|
||||
return 1
|
||||
}
|
||||
// amd64:`CMPB command-line-arguments.x8\+1\(SB\), [$]7`
|
||||
if x8[1] == 7 {
|
||||
return 1
|
||||
}
|
||||
// amd64:`CMPW command-line-arguments.x16\+2\(SB\), [$]7`
|
||||
if x16[1] == 7 {
|
||||
return 1
|
||||
}
|
||||
// amd64:`CMPL command-line-arguments.x32\+4\(SB\), [$]7`
|
||||
if x32[1] == 7 {
|
||||
return 1
|
||||
}
|
||||
// amd64:`CMPQ command-line-arguments.x64\+8\(SB\), [$]7`
|
||||
if x64[1] == 7 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type T struct {
|
||||
x bool
|
||||
x8 uint8
|
||||
x16 uint16
|
||||
x32 uint32
|
||||
x64 uint64
|
||||
a [2]int // force it passed in memory
|
||||
}
|
||||
|
||||
func compMem2(t T) int {
|
||||
// amd64:`CMPB .*\(SP\), [$]0`
|
||||
if t.x {
|
||||
return 1
|
||||
}
|
||||
// amd64:`CMPB .*\(SP\), [$]7`
|
||||
if t.x8 == 7 {
|
||||
return 1
|
||||
}
|
||||
// amd64:`CMPW .*\(SP\), [$]7`
|
||||
if t.x16 == 7 {
|
||||
return 1
|
||||
}
|
||||
// amd64:`CMPL .*\(SP\), [$]7`
|
||||
if t.x32 == 7 {
|
||||
return 1
|
||||
}
|
||||
// amd64:`CMPQ .*\(SP\), [$]7`
|
||||
if t.x64 == 7 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func compMem3(x, y *int) (int, bool) {
|
||||
// We can do comparisons of a register with memory even if
|
||||
// the register is used subsequently.
|
||||
r := *x
|
||||
// amd64:`CMPQ \(`
|
||||
// 386:`CMPL \(`
|
||||
return r, r < *y
|
||||
}
|
||||
|
||||
// The following functions test that indexed load/store operations get generated.
|
||||
|
||||
func idxInt8(x, y []int8, i int) {
|
||||
var t int8
|
||||
// amd64: `MOVBL[SZ]X 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*`
|
||||
// 386: `MOVBL[SZ]X 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*`
|
||||
t = x[i+1]
|
||||
// amd64: `MOVB [A-Z]+[0-9]*, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)`
|
||||
// 386: `MOVB [A-Z]+[0-9]*, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)`
|
||||
y[i+1] = t
|
||||
// amd64: `MOVB [$]77, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)`
|
||||
// 386: `MOVB [$]77, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)`
|
||||
x[i+1] = 77
|
||||
}
|
||||
|
||||
func idxInt16(x, y []int16, i int) {
|
||||
var t int16
|
||||
// amd64: `MOVWL[SZ]X 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*`
|
||||
// 386: `MOVWL[SZ]X 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*`
|
||||
t = x[i+1]
|
||||
// amd64: `MOVW [A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)`
|
||||
// 386: `MOVW [A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)`
|
||||
y[i+1] = t
|
||||
// amd64: `MOVWL[SZ]X 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*`
|
||||
// 386: `MOVWL[SZ]X 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*`
|
||||
t = x[16*i+1]
|
||||
// amd64: `MOVW [A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)`
|
||||
// 386: `MOVW [A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)`
|
||||
y[16*i+1] = t
|
||||
// amd64: `MOVW [$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)`
|
||||
// 386: `MOVW [$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)`
|
||||
x[i+1] = 77
|
||||
// amd64: `MOVW [$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)`
|
||||
// 386: `MOVW [$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)`
|
||||
x[16*i+1] = 77
|
||||
}
|
||||
|
||||
func idxInt32(x, y []int32, i int) {
|
||||
var t int32
|
||||
// amd64: `MOVL 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
// 386: `MOVL 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
t = x[i+1]
|
||||
// amd64: `MOVL [A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
// 386: `MOVL [A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
y[i+1] = t
|
||||
// amd64: `MOVL 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
t = x[2*i+1]
|
||||
// amd64: `MOVL [A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
y[2*i+1] = t
|
||||
// amd64: `MOVL 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*`
|
||||
// 386: `MOVL 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*`
|
||||
t = x[16*i+1]
|
||||
// amd64: `MOVL [A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)`
|
||||
// 386: `MOVL [A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)`
|
||||
y[16*i+1] = t
|
||||
// amd64: `MOVL [$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
// 386: `MOVL [$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+1] = 77
|
||||
// amd64: `MOVL [$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)`
|
||||
// 386: `MOVL [$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)`
|
||||
x[16*i+1] = 77
|
||||
}
|
||||
|
||||
func idxInt64(x, y []int64, i int) {
|
||||
var t int64
|
||||
// amd64: `MOVQ 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
t = x[i+1]
|
||||
// amd64: `MOVQ [A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
y[i+1] = t
|
||||
// amd64: `MOVQ 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), [A-Z]+[0-9]*`
|
||||
t = x[16*i+1]
|
||||
// amd64: `MOVQ [A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)`
|
||||
y[16*i+1] = t
|
||||
// amd64: `MOVQ [$]77, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+1] = 77
|
||||
// amd64: `MOVQ [$]77, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)`
|
||||
x[16*i+1] = 77
|
||||
}
|
||||
|
||||
func idxFloat32(x, y []float32, i int) {
|
||||
var t float32
|
||||
// amd64: `MOVSS 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+`
|
||||
// 386/sse2: `MOVSS 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+`
|
||||
// arm64: `FMOVS \(R[0-9]*\)\(R[0-9]*<<2\), F[0-9]+`
|
||||
t = x[i+1]
|
||||
// amd64: `MOVSS X[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
// 386/sse2: `MOVSS X[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
// arm64: `FMOVS F[0-9]+, \(R[0-9]*\)\(R[0-9]*<<2\)`
|
||||
y[i+1] = t
|
||||
// amd64: `MOVSS 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+`
|
||||
// 386/sse2: `MOVSS 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+`
|
||||
t = x[16*i+1]
|
||||
// amd64: `MOVSS X[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)`
|
||||
// 386/sse2: `MOVSS X[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)`
|
||||
y[16*i+1] = t
|
||||
}
|
||||
|
||||
func idxFloat64(x, y []float64, i int) {
|
||||
var t float64
|
||||
// amd64: `MOVSD 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+`
|
||||
// 386/sse2: `MOVSD 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+`
|
||||
// arm64: `FMOVD \(R[0-9]*\)\(R[0-9]*<<3\), F[0-9]+`
|
||||
t = x[i+1]
|
||||
// amd64: `MOVSD X[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
// 386/sse2: `MOVSD X[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
// arm64: `FMOVD F[0-9]+, \(R[0-9]*\)\(R[0-9]*<<3\)`
|
||||
y[i+1] = t
|
||||
// amd64: `MOVSD 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+`
|
||||
// 386/sse2: `MOVSD 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+`
|
||||
t = x[16*i+1]
|
||||
// amd64: `MOVSD X[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)`
|
||||
// 386/sse2: `MOVSD X[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)`
|
||||
y[16*i+1] = t
|
||||
}
|
||||
|
||||
func idxLoadPlusOp32(x []int32, i int) int32 {
|
||||
s := x[0]
|
||||
// 386: `ADDL 4\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+`
|
||||
// amd64: `ADDL 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s += x[i+1]
|
||||
// 386: `SUBL 8\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+`
|
||||
// amd64: `SUBL 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s -= x[i+2]
|
||||
// 386: `IMULL 12\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+`
|
||||
s *= x[i+3]
|
||||
// 386: `ANDL 16\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+`
|
||||
// amd64: `ANDL 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s &= x[i+4]
|
||||
// 386: `ORL 20\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+`
|
||||
// amd64: `ORL 20\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s |= x[i+5]
|
||||
// 386: `XORL 24\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+`
|
||||
// amd64: `XORL 24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
s ^= x[i+6]
|
||||
return s
|
||||
}
|
||||
|
||||
func idxLoadPlusOp64(x []int64, i int) int64 {
|
||||
s := x[0]
|
||||
// amd64: `ADDQ 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s += x[i+1]
|
||||
// amd64: `SUBQ 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s -= x[i+2]
|
||||
// amd64: `ANDQ 24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s &= x[i+3]
|
||||
// amd64: `ORQ 32\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s |= x[i+4]
|
||||
// amd64: `XORQ 40\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
s ^= x[i+5]
|
||||
return s
|
||||
}
|
||||
|
||||
func idxStorePlusOp32(x []int32, i int, v int32) {
|
||||
// 386: `ADDL [A-Z]+, 4\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `ADDL [A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+1] += v
|
||||
// 386: `SUBL [A-Z]+, 8\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `SUBL [A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+2] -= v
|
||||
// 386: `ANDL [A-Z]+, 12\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `ANDL [A-Z]+[0-9]*, 12\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+3] &= v
|
||||
// 386: `ORL [A-Z]+, 16\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `ORL [A-Z]+[0-9]*, 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+4] |= v
|
||||
// 386: `XORL [A-Z]+, 20\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `XORL [A-Z]+[0-9]*, 20\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+5] ^= v
|
||||
|
||||
// 386: `ADDL [$]77, 24\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `ADDL [$]77, 24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+6] += 77
|
||||
// 386: `ANDL [$]77, 28\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `ANDL [$]77, 28\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+7] &= 77
|
||||
// 386: `ORL [$]77, 32\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `ORL [$]77, 32\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+8] |= 77
|
||||
// 386: `XORL [$]77, 36\([A-Z]+\)\([A-Z]+\*4\)`
|
||||
// amd64: `XORL [$]77, 36\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)`
|
||||
x[i+9] ^= 77
|
||||
}
|
||||
|
||||
func idxStorePlusOp64(x []int64, i int, v int64) {
|
||||
// amd64: `ADDQ [A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+1] += v
|
||||
// amd64: `SUBQ [A-Z]+[0-9]*, 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+2] -= v
|
||||
// amd64: `ANDQ [A-Z]+[0-9]*, 24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+3] &= v
|
||||
// amd64: `ORQ [A-Z]+[0-9]*, 32\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+4] |= v
|
||||
// amd64: `XORQ [A-Z]+[0-9]*, 40\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+5] ^= v
|
||||
|
||||
// amd64: `ADDQ [$]77, 48\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+6] += 77
|
||||
// amd64: `ANDQ [$]77, 56\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+7] &= 77
|
||||
// amd64: `ORQ [$]77, 64\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+8] |= 77
|
||||
// amd64: `XORQ [$]77, 72\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)`
|
||||
x[i+9] ^= 77
|
||||
}
|
||||
|
||||
func idxCompare(i int) int {
|
||||
// amd64: `MOVBLZX 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*`
|
||||
if x8[i+1] < x8[0] {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVWLZX 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*`
|
||||
if x16[i+1] < x16[0] {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVWLZX 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*`
|
||||
if x16[16*i+1] < x16[0] {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVL 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
if x32[i+1] < x32[0] {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVL 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*`
|
||||
if x32[16*i+1] < x32[0] {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVQ 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
if x64[i+1] < x64[0] {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVQ 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), [A-Z]+[0-9]*`
|
||||
if x64[16*i+1] < x64[0] {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVBLZX 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*`
|
||||
if x8[i+2] < 77 {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVWLZX 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*`
|
||||
if x16[i+2] < 77 {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVWLZX 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*`
|
||||
if x16[16*i+2] < 77 {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVL 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*`
|
||||
if x32[i+2] < 77 {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVL 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*`
|
||||
if x32[16*i+2] < 77 {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVQ 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*`
|
||||
if x64[i+2] < 77 {
|
||||
return 0
|
||||
}
|
||||
// amd64: `MOVQ 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), [A-Z]+[0-9]*`
|
||||
if x64[16*i+2] < 77 {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func idxFloatOps(a []float64, b []float32, i int) (float64, float32) {
|
||||
c := float64(7)
|
||||
// amd64: `ADDSD 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+`
|
||||
c += a[i+1]
|
||||
// amd64: `SUBSD 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+`
|
||||
c -= a[i+2]
|
||||
// amd64: `MULSD 24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+`
|
||||
c *= a[i+3]
|
||||
// amd64: `DIVSD 32\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+`
|
||||
c /= a[i+4]
|
||||
|
||||
d := float32(8)
|
||||
// amd64: `ADDSS 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+`
|
||||
d += b[i+1]
|
||||
// amd64: `SUBSS 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+`
|
||||
d -= b[i+2]
|
||||
// amd64: `MULSS 12\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+`
|
||||
d *= b[i+3]
|
||||
// amd64: `DIVSS 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+`
|
||||
d /= b[i+4]
|
||||
return c, d
|
||||
}
|
||||
|
||||
func storeTest(a []bool, v int, i int) {
|
||||
// amd64: `BTL \$0,`,`SETCS 4\([A-Z]+[0-9]*\)`
|
||||
a[4] = v&1 != 0
|
||||
// amd64: `BTL \$1,`,`SETCS 3\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)`
|
||||
a[3+i] = v&2 != 0
|
||||
}
|
||||
|
||||
func bitOps(p *[12]uint64) {
|
||||
// amd64: `ORQ \$8, \(AX\)`
|
||||
p[0] |= 8
|
||||
// amd64: `ORQ \$1073741824, 8\(AX\)`
|
||||
p[1] |= 1 << 30
|
||||
// amd64: `BTSQ \$31, 16\(AX\)`
|
||||
p[2] |= 1 << 31
|
||||
// amd64: `BTSQ \$63, 24\(AX\)`
|
||||
p[3] |= 1 << 63
|
||||
|
||||
// amd64: `ANDQ \$-9, 32\(AX\)`
|
||||
p[4] &^= 8
|
||||
// amd64: `ANDQ \$-1073741825, 40\(AX\)`
|
||||
p[5] &^= 1 << 30
|
||||
// amd64: `BTRQ \$31, 48\(AX\)`
|
||||
p[6] &^= 1 << 31
|
||||
// amd64: `BTRQ \$63, 56\(AX\)`
|
||||
p[7] &^= 1 << 63
|
||||
|
||||
// amd64: `XORQ \$8, 64\(AX\)`
|
||||
p[8] ^= 8
|
||||
// amd64: `XORQ \$1073741824, 72\(AX\)`
|
||||
p[9] ^= 1 << 30
|
||||
// amd64: `BTCQ \$31, 80\(AX\)`
|
||||
p[10] ^= 1 << 31
|
||||
// amd64: `BTCQ \$63, 88\(AX\)`
|
||||
p[11] ^= 1 << 63
|
||||
}
|
||||
71
test/codegen/memops_bigoffset.go
Normal file
71
test/codegen/memops_bigoffset.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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
|
||||
|
||||
type big1 struct {
|
||||
w [1<<30 - 1]uint32
|
||||
}
|
||||
type big2 struct {
|
||||
d [1<<29 - 1]uint64
|
||||
}
|
||||
|
||||
func loadLargeOffset(sw *big1, sd *big2) (uint32, uint64) {
|
||||
|
||||
// ppc64x:`MOVWZ\s+[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
a3 := sw.w[1<<10]
|
||||
// ppc64le/power10:`MOVWZ\s+[0-9]+\(R[0-9]+\),\sR[0-9]+`,-`ADD`
|
||||
// ppc64x/power9:`ADD`,`MOVWZ\s+\(R[0-9]+\),\sR[0-9]+`
|
||||
// ppc64x/power8:`ADD`,`MOVWZ\s+\(R[0-9]+\),\sR[0-9]+`
|
||||
b3 := sw.w[1<<16]
|
||||
// ppc64le/power10:`MOVWZ\s+[0-9]+\(R[0-9]+\),\sR[0-9]+`,-`ADD`
|
||||
// ppc64x/power9:`ADD`,`MOVWZ\s+\(R[0-9]+\),\sR[0-9]+`
|
||||
// ppc64x/power8:`ADD`,`MOVWZ\s+\(R[0-9]+\),\sR[0-9]+`
|
||||
c3 := sw.w[1<<28]
|
||||
// ppc64x:`MOVWZ\s+\(R[0-9]+\)\(R[0-9]+\),\sR[0-9]+`
|
||||
d3 := sw.w[1<<29]
|
||||
// ppc64x:`MOVD\s+[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
a4 := sd.d[1<<10]
|
||||
// ppc64le/power10:`MOVD\s+[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
// ppc64x/power9:`ADD`,`MOVD\s+\(R[0-9]+\),\sR[0-9]+`
|
||||
// ppc64x/power8:`ADD`,`MOVD\s+\(R[0-9]+\),\sR[0-9]+`
|
||||
b4 := sd.d[1<<16]
|
||||
// ppc64le/power10`:`MOVD\s+[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
// ppc64x/power9:`ADD`,`MOVD\s+\(R[0-9]+\),\sR[0-9]+`
|
||||
// ppc64x/power8:`ADD`,`MOVD\s+\(R[0-9]+\),\sR[0-9]+`
|
||||
c4 := sd.d[1<<27]
|
||||
// ppc64x:`MOVD\s+\(R[0-9]+\)\(R[0-9]+\),\sR[0-9]+`
|
||||
d4 := sd.d[1<<28]
|
||||
|
||||
return a3 + b3 + c3 + d3, a4 + b4 + c4 + d4
|
||||
}
|
||||
|
||||
func storeLargeOffset(sw *big1, sd *big2) {
|
||||
// ppc64x:`MOVW\s+R[0-9]+,\s[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
sw.w[1<<10] = uint32(10)
|
||||
// ppc64le/power10:`MOVW\s+R[0-9]+,\s[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
// ppc64x/power9:`MOVW\s+R[0-9]+\,\s\(R[0-9]+\)`,`ADD`
|
||||
// ppc64x/power8:`MOVW\s+R[0-9]+\,\s\(R[0-9]+\)`,`ADD`
|
||||
sw.w[1<<16] = uint32(20)
|
||||
// ppc64le/power10:`MOVW\s+R[0-9]+,\s[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
// ppc64x/power9:`MOVW\s+R[0-9]+,\s\(R[0-9]+\)`,`ADD`
|
||||
// ppc64x/power8:`MOVW\s+R[0-9]+,\s\(R[0-9]+\)`,`ADD`
|
||||
sw.w[1<<28] = uint32(30)
|
||||
// ppc64x:`MOVW\s+R[0-9]+,\s\(R[0-9]+\)`
|
||||
sw.w[1<<29] = uint32(40)
|
||||
// ppc64x:`MOVD\s+R[0-9]+,\s[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
sd.d[1<<10] = uint64(40)
|
||||
// ppc64le/power10:`MOVD\s+R[0-9]+,\s[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
// ppc64x/power9:`MOVD\s+R[0-9]+,\s\(R[0-9]+\)`,`ADD`
|
||||
// ppc64x/power8:`MOVD\s+R[0-9]+,\s\(R[0-9]+\)`,`ADD`
|
||||
sd.d[1<<16] = uint64(50)
|
||||
// ppc64le/power10`:`MOVD\s+R[0-9]+,\s[0-9]+\(R[0-9]+\)`,-`ADD`
|
||||
// ppc64x/power9:`MOVD\s+R[0-9]+,\s\(R[0-9]+\)`,`ADD`
|
||||
// ppc64x/power8:`MOVD\s+R[0-9]+,\s\(R[0-9]+\)`,`ADD`
|
||||
sd.d[1<<27] = uint64(60)
|
||||
// ppc64x:`MOVD\s+R[0-9]+,\s\(R[0-9]+\)`
|
||||
sd.d[1<<28] = uint64(70)
|
||||
}
|
||||
372
test/codegen/multiply.go
Normal file
372
test/codegen/multiply.go
Normal file
@@ -0,0 +1,372 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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
|
||||
|
||||
// This file contains codegen tests related to strength
|
||||
// reduction of integer multiply.
|
||||
|
||||
func m0(x int64) int64 {
|
||||
// amd64: "XORL"
|
||||
// arm64: "MOVD ZR"
|
||||
// loong64: "MOVV R0"
|
||||
return x * 0
|
||||
}
|
||||
func m2(x int64) int64 {
|
||||
// amd64: "ADDQ"
|
||||
// arm64: "ADD"
|
||||
// loong64: "ADDVU"
|
||||
return x * 2
|
||||
}
|
||||
func m3(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]2"
|
||||
// arm64: "ADD R[0-9]+<<1,"
|
||||
// loong64: "ALSLV [$]1,"
|
||||
return x * 3
|
||||
}
|
||||
func m4(x int64) int64 {
|
||||
// amd64: "SHLQ [$]2,"
|
||||
// arm64: "LSL [$]2,"
|
||||
// loong64: "SLLV [$]2,"
|
||||
return x * 4
|
||||
}
|
||||
func m5(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]4"
|
||||
// arm64: "ADD R[0-9]+<<2,"
|
||||
// loong64: "ALSLV [$]2,"
|
||||
return x * 5
|
||||
}
|
||||
func m6(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]1", "LEAQ .*[*]2"
|
||||
// arm64: "ADD R[0-9]+,", "ADD R[0-9]+<<1,"
|
||||
// loong64: "ADDVU", "ADDVU", "ADDVU"
|
||||
return x * 6
|
||||
}
|
||||
func m7(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]2"
|
||||
// arm64: "LSL [$]3,", "SUB R[0-9]+,"
|
||||
// loong64: "ALSLV [$]1,", "ALSLV [$]1,"
|
||||
return x * 7
|
||||
}
|
||||
func m8(x int64) int64 {
|
||||
// amd64: "SHLQ [$]3,"
|
||||
// arm64: "LSL [$]3,"
|
||||
// loong64: "SLLV [$]3,"
|
||||
return x * 8
|
||||
}
|
||||
func m9(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]8"
|
||||
// arm64: "ADD R[0-9]+<<3,"
|
||||
// loong64: "ALSLV [$]3,"
|
||||
return x * 9
|
||||
}
|
||||
func m10(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]1", "LEAQ .*[*]4"
|
||||
// arm64: "ADD R[0-9]+,", "ADD R[0-9]+<<2,"
|
||||
// loong64: "ADDVU", "ALSLV [$]2,"
|
||||
return x * 10
|
||||
}
|
||||
func m11(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]4", "LEAQ .*[*]2"
|
||||
// arm64: "MOVD [$]11,", "MUL"
|
||||
// loong64: "ALSLV [$]2,", "ALSLV [$]1,"
|
||||
return x * 11
|
||||
}
|
||||
func m12(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]2", "SHLQ [$]2,"
|
||||
// arm64: "LSL [$]2,", "ADD R[0-9]+<<1,"
|
||||
// loong64: "SLLV", "ALSLV [$]1,"
|
||||
return x * 12
|
||||
}
|
||||
func m13(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]2", "LEAQ .*[*]4"
|
||||
// arm64: "MOVD [$]13,", "MUL"
|
||||
// loong64: "ALSLV [$]1,", "ALSLV [$]2,"
|
||||
return x * 13
|
||||
}
|
||||
func m14(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]14,"
|
||||
// arm64: "LSL [$]4,", "SUB R[0-9]+<<1,"
|
||||
// loong64: "ADDVU", "ALSLV [$]1", "ALSLV [$]2"
|
||||
return x * 14
|
||||
}
|
||||
func m15(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]2", "LEAQ .*[*]4"
|
||||
// arm64: "LSL [$]4,", "SUB R[0-9]+,"
|
||||
// loong64: "ALSLV [$]1,", "ALSLV [$]2,"
|
||||
return x * 15
|
||||
}
|
||||
func m16(x int64) int64 {
|
||||
// amd64: "SHLQ [$]4,"
|
||||
// arm64: "LSL [$]4,"
|
||||
// loong64: "SLLV [$]4,"
|
||||
return x * 16
|
||||
}
|
||||
func m17(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]1", "LEAQ .*[*]8"
|
||||
// arm64: "ADD R[0-9]+<<4,"
|
||||
// loong64: "ALSLV [$]"
|
||||
return x * 17
|
||||
}
|
||||
func m18(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]1", "LEAQ .*[*]8"
|
||||
// arm64: "ADD R[0-9]+,", "ADD R[0-9]+<<3,"
|
||||
// loong64: "ADDVU", "ALSLV [$]3,"
|
||||
return x * 18
|
||||
}
|
||||
func m19(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]8", "LEAQ .*[*]2"
|
||||
// arm64: "MOVD [$]19,", "MUL"
|
||||
// loong64: "ALSLV [$]3,", "ALSLV [$]1,"
|
||||
return x * 19
|
||||
}
|
||||
func m20(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]4", "SHLQ [$]2,"
|
||||
// arm64: "LSL [$]2,", "ADD R[0-9]+<<2,"
|
||||
// loong64: "SLLV [$]2,", "ALSLV [$]2,"
|
||||
return x * 20
|
||||
}
|
||||
func m21(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]4", "LEAQ .*[*]4"
|
||||
// arm64: "MOVD [$]21,", "MUL"
|
||||
// loong64: "ALSLV [$]2,", "ALSLV [$]2,"
|
||||
return x * 21
|
||||
}
|
||||
func m22(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]22,"
|
||||
// arm64: "MOVD [$]22,", "MUL"
|
||||
// loong64: "ADDVU", "ALSLV [$]2,", "ALSLV [$]2,"
|
||||
return x * 22
|
||||
}
|
||||
func m23(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]23,"
|
||||
// arm64: "MOVD [$]23,", "MUL"
|
||||
// loong64: "ALSLV [$]1,", "SUBVU", "ALSLV [$]3,"
|
||||
return x * 23
|
||||
}
|
||||
func m24(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]2", "SHLQ [$]3,"
|
||||
// arm64: "LSL [$]3,", "ADD R[0-9]+<<1,"
|
||||
// loong64: "SLLV [$]3", "ALSLV [$]1,"
|
||||
return x * 24
|
||||
}
|
||||
func m25(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]4", "LEAQ .*[*]4"
|
||||
// arm64: "MOVD [$]25,", "MUL"
|
||||
// loong64: "ALSLV [$]2,", "ALSLV [$]2,"
|
||||
return x * 25
|
||||
}
|
||||
func m26(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]26,"
|
||||
// arm64: "MOVD [$]26,", "MUL"
|
||||
// loong64: "ADDVU", "ALSLV [$]1,", "ALSLV [$]3,"
|
||||
return x * 26
|
||||
}
|
||||
func m27(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]2", "LEAQ .*[*]8"
|
||||
// arm64: "MOVD [$]27,", "MUL"
|
||||
// loong64: "ALSLV [$]1,", "ALSLV [$]3,"
|
||||
return x * 27
|
||||
}
|
||||
func m28(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]28,"
|
||||
// arm64: "LSL [$]5, "SUB R[0-9]+<<2,"
|
||||
// loong64: "ALSLV [$]1," "SLLV [$]2," "ALSLV [$]3,"
|
||||
return x * 28
|
||||
}
|
||||
func m29(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]29,"
|
||||
// arm64: "MOVD [$]29,", "MUL"
|
||||
// loong64: "ALSLV [$]1," "SLLV [$]5," "SUBVU"
|
||||
return x * 29
|
||||
}
|
||||
func m30(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]30,"
|
||||
// arm64: "LSL [$]5,", "SUB R[0-9]+<<1,"
|
||||
// loong64: "ADDVU" "SLLV [$]5," "SUBVU"
|
||||
return x * 30
|
||||
}
|
||||
func m31(x int64) int64 {
|
||||
// amd64: "SHLQ [$]5,", "SUBQ"
|
||||
// arm64: "LSL [$]5,", "SUB R[0-9]+,"
|
||||
// loong64: "SLLV [$]5," "SUBVU"
|
||||
return x * 31
|
||||
}
|
||||
func m32(x int64) int64 {
|
||||
// amd64: "SHLQ [$]5,"
|
||||
// arm64: "LSL [$]5,"
|
||||
// loong64: "SLLV [$]5,"
|
||||
return x * 32
|
||||
}
|
||||
func m33(x int64) int64 {
|
||||
// amd64: "SHLQ [$]2,", "LEAQ .*[*]8"
|
||||
// arm64: "ADD R[0-9]+<<5,"
|
||||
// loong64: "ADDVU", "ALSLV [$]4,"
|
||||
return x * 33
|
||||
}
|
||||
func m34(x int64) int64 {
|
||||
// amd64: "SHLQ [$]5,", "LEAQ .*[*]2"
|
||||
// arm64: "ADD R[0-9]+,", "ADD R[0-9]+<<4,"
|
||||
// loong64: "ADDVU", "ALSLV [$]4,"
|
||||
return x * 34
|
||||
}
|
||||
func m35(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]35,"
|
||||
// arm64: "MOVD [$]35,", "MUL"
|
||||
// loong64: "ALSLV [$]4,", "ALSLV [$]1,"
|
||||
return x * 35
|
||||
}
|
||||
func m36(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]8", "SHLQ [$]2,"
|
||||
// arm64: "LSL [$]2,", "ADD R[0-9]+<<3,"
|
||||
// loong64: "SLLV [$]2,", "ALSLV [$]3,"
|
||||
return x * 36
|
||||
}
|
||||
func m37(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]8", "LEAQ .*[*]4"
|
||||
// arm64: "MOVD [$]37,", "MUL"
|
||||
// loong64: "ALSLV [$]3,", "ALSLV [$]2,"
|
||||
return x * 37
|
||||
}
|
||||
func m38(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]38,"
|
||||
// arm64: "MOVD [$]38,", "MUL"
|
||||
// loong64: "ALSLV [$]3,", "ALSLV [$]2,"
|
||||
return x * 38
|
||||
}
|
||||
func m39(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]39,"
|
||||
// arm64: "MOVD [$]39,", "MUL"
|
||||
// loong64: "ALSLV [$]2,", "SUBVU", "ALSLV [$]3,"
|
||||
return x * 39
|
||||
}
|
||||
func m40(x int64) int64 {
|
||||
// amd64: "LEAQ .*[*]4", "SHLQ [$]3,"
|
||||
// arm64: "LSL [$]3,", "ADD R[0-9]+<<2,"
|
||||
// loong64: "SLLV [$]3,", "ALSLV [$]2,"
|
||||
return x * 40
|
||||
}
|
||||
|
||||
func mn1(x int64) int64 {
|
||||
// amd64: "NEGQ "
|
||||
// arm64: "NEG R[0-9]+,"
|
||||
// loong64: "SUBVU R[0-9], R0,"
|
||||
return x * -1
|
||||
}
|
||||
func mn2(x int64) int64 {
|
||||
// amd64: "NEGQ", "ADDQ"
|
||||
// arm64: "NEG R[0-9]+<<1,"
|
||||
// loong64: "ADDVU" "SUBVU R[0-9], R0,"
|
||||
return x * -2
|
||||
}
|
||||
func mn3(x int64) int64 {
|
||||
// amd64: "NEGQ", "LEAQ .*[*]2"
|
||||
// arm64: "SUB R[0-9]+<<2,"
|
||||
// loong64: "SUBVU", "ALSLV [$]1,"
|
||||
return x * -3
|
||||
}
|
||||
func mn4(x int64) int64 {
|
||||
// amd64: "NEGQ", "SHLQ [$]2,"
|
||||
// arm64: "NEG R[0-9]+<<2,"
|
||||
// loong64: "SLLV [$]2," "SUBVU R[0-9], R0,"
|
||||
return x * -4
|
||||
}
|
||||
func mn5(x int64) int64 {
|
||||
// amd64: "NEGQ", "LEAQ .*[*]4"
|
||||
// arm64: "NEG R[0-9]+,", "ADD R[0-9]+<<2,"
|
||||
// loong64: "SUBVU", "ALSLV [$]2,"
|
||||
return x * -5
|
||||
}
|
||||
func mn6(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-6,"
|
||||
// arm64: "ADD R[0-9]+,", "SUB R[0-9]+<<2,"
|
||||
// loong64: "ADDVU", "SUBVU", "ALSLV [$]3,"
|
||||
return x * -6
|
||||
}
|
||||
func mn7(x int64) int64 {
|
||||
// amd64: "NEGQ", "LEAQ .*[*]8"
|
||||
// arm64: "SUB R[0-9]+<<3,"
|
||||
// loong64: "SUBVU", "ALSLV [$]3,"
|
||||
return x * -7
|
||||
}
|
||||
func mn8(x int64) int64 {
|
||||
// amd64: "NEGQ", "SHLQ [$]3,"
|
||||
// arm64: "NEG R[0-9]+<<3,"
|
||||
// loong64: "SLLV [$]3" "SUBVU R[0-9], R0,"
|
||||
return x * -8
|
||||
}
|
||||
func mn9(x int64) int64 {
|
||||
// amd64: "NEGQ", "LEAQ .*[*]8"
|
||||
// arm64: "NEG R[0-9]+,", "ADD R[0-9]+<<3,"
|
||||
// loong64: "SUBVU", "ALSLV [$]3,"
|
||||
return x * -9
|
||||
}
|
||||
func mn10(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-10,"
|
||||
// arm64: "MOVD [$]-10,", "MUL"
|
||||
// loong64: "ADDVU", "ALSLV [$]3", "SUBVU"
|
||||
return x * -10
|
||||
}
|
||||
func mn11(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-11,"
|
||||
// arm64: "MOVD [$]-11,", "MUL"
|
||||
// loong64: "ALSLV [$]2,", "SUBVU", "ALSLV [$]4,"
|
||||
return x * -11
|
||||
}
|
||||
func mn12(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-12,"
|
||||
// arm64: "LSL [$]2,", "SUB R[0-9]+<<2,"
|
||||
// loong64: "SUBVU", "SLLV [$]2,", "ALSLV [$]4,"
|
||||
return x * -12
|
||||
}
|
||||
func mn13(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-13,"
|
||||
// arm64: "MOVD [$]-13,", "MUL"
|
||||
// loong64: "ALSLV [$]4,", "SLLV [$]2, ", "SUBVU"
|
||||
return x * -13
|
||||
}
|
||||
func mn14(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-14,"
|
||||
// arm64: "ADD R[0-9]+,", "SUB R[0-9]+<<3,"
|
||||
// loong64: "ADDVU", "SUBVU", "ALSLV [$]4,"
|
||||
return x * -14
|
||||
}
|
||||
func mn15(x int64) int64 {
|
||||
// amd64: "SHLQ [$]4,", "SUBQ"
|
||||
// arm64: "SUB R[0-9]+<<4,"
|
||||
// loong64: "SUBVU", "ALSLV [$]4,"
|
||||
return x * -15
|
||||
}
|
||||
func mn16(x int64) int64 {
|
||||
// amd64: "NEGQ", "SHLQ [$]4,"
|
||||
// arm64: "NEG R[0-9]+<<4,"
|
||||
// loong64: "SLLV [$]4," "SUBVU R[0-9], R0,"
|
||||
return x * -16
|
||||
}
|
||||
func mn17(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-17,"
|
||||
// arm64: "NEG R[0-9]+,", "ADD R[0-9]+<<4,"
|
||||
// loong64: "SUBVU", "ALSLV [$]4,"
|
||||
return x * -17
|
||||
}
|
||||
func mn18(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-18,"
|
||||
// arm64: "MOVD [$]-18,", "MUL"
|
||||
// loong64: "ADDVU", "ALSLV [$]4,", "SUBVU"
|
||||
return x * -18
|
||||
}
|
||||
func mn19(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-19,"
|
||||
// arm64: "MOVD [$]-19,", "MUL"
|
||||
// loong64: "ALSLV [$]1,", "ALSLV [$]4,", "SUBVU"
|
||||
return x * -19
|
||||
}
|
||||
func mn20(x int64) int64 {
|
||||
// amd64: "IMUL3Q [$]-20,"
|
||||
// arm64: "MOVD [$]-20,", "MUL"
|
||||
// loong64: "SLLV [$]2,", "ALSLV [$]4,", "SUBVU"
|
||||
return x * -20
|
||||
}
|
||||
285
test/codegen/noextend.go
Normal file
285
test/codegen/noextend.go
Normal file
@@ -0,0 +1,285 @@
|
||||
// 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 "math/bits"
|
||||
|
||||
var sval64 [8]int64
|
||||
var sval32 [8]int32
|
||||
var sval16 [8]int16
|
||||
var sval8 [8]int8
|
||||
var val64 [8]uint64
|
||||
var val32 [8]uint32
|
||||
var val16 [8]uint16
|
||||
var val8 [8]uint8
|
||||
|
||||
// Avoid zero/sign extensions following a load
|
||||
// which has extended the value correctly.
|
||||
// Note: No tests are done for int8 since
|
||||
// an extra extension is usually needed due to
|
||||
// no signed byte load.
|
||||
|
||||
func set16(x8 int8, u8 *uint8, y8 int8, z8 uint8) {
|
||||
// Truncate not needed, load does sign/zero extend
|
||||
|
||||
// ppc64x:-"MOVBZ R\\d+,\\sR\\d+"
|
||||
val16[0] = uint16(*u8)
|
||||
|
||||
// AND not needed due to size
|
||||
// ppc64x:-"ANDCC"
|
||||
sval16[1] = 255 & int16(x8+y8)
|
||||
|
||||
// ppc64x:-"ANDCC"
|
||||
val16[1] = 255 & uint16(*u8+z8)
|
||||
|
||||
}
|
||||
func shiftidx(u8 *uint8, x16 *int16, u16 *uint16) {
|
||||
|
||||
// ppc64x:-"MOVBZ R\\d+,\\sR\\d+"
|
||||
val16[0] = uint16(sval16[*u8>>2])
|
||||
|
||||
// ppc64x:-"MOVH R\\d+,\\sR\\d+"
|
||||
sval16[1] = int16(val16[*x16>>1])
|
||||
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
val16[1] = uint16(sval16[*u16>>2])
|
||||
|
||||
}
|
||||
|
||||
func setnox(x8 int8, u8 *uint8, y8 *int8, z8 *uint8, x16 *int16, u16 *uint16, x32 *int32, u32 *uint32) {
|
||||
|
||||
// ppc64x:-"MOVBZ R\\d+,\\sR\\d+"
|
||||
val16[0] = uint16(*u8)
|
||||
|
||||
// AND not needed due to size
|
||||
// ppc64x:-"ANDCC"
|
||||
sval16[1] = 255 & int16(x8+*y8)
|
||||
|
||||
// ppc64x:-"ANDCC"
|
||||
val16[1] = 255 & uint16(*u8+*z8)
|
||||
|
||||
// ppc64x:-"MOVH R\\d+,\\sR\\d+"
|
||||
sval32[1] = int32(*x16)
|
||||
|
||||
// ppc64x:-"MOVBZ R\\d+,\\sR\\d+"
|
||||
val32[0] = uint32(*u8)
|
||||
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
val32[1] = uint32(*u16)
|
||||
|
||||
// ppc64x:-"MOVH R\\d+,\\sR\\d+"
|
||||
sval64[1] = int64(*x16)
|
||||
|
||||
// ppc64x:-"MOVW R\\d+,\\sR\\d+"
|
||||
sval64[2] = int64(*x32)
|
||||
|
||||
// ppc64x:-"MOVBZ R\\d+,\\sR\\d+"
|
||||
val64[0] = uint64(*u8)
|
||||
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
val64[1] = uint64(*u16)
|
||||
|
||||
// ppc64x:-"MOVWZ R\\d+,\\sR\\d+"
|
||||
val64[2] = uint64(*u32)
|
||||
}
|
||||
|
||||
func cmp16(u8 *uint8, x32 *int32, u32 *uint32, x64 *int64, u64 *uint64) bool {
|
||||
|
||||
// ppc64x:-"MOVBZ R\\d+,\\sR\\d+"
|
||||
if uint16(*u8) == val16[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
if uint16(*u32>>16) == val16[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
if uint16(*u64>>48) == val16[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// Verify the truncates are using the correct sign.
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
if int16(*x32) == sval16[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVH R\\d+,\\sR\\d+"
|
||||
if uint16(*u32) == val16[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
if int16(*x64) == sval16[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVH R\\d+,\\sR\\d+"
|
||||
if uint16(*u64) == val16[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func cmp32(u8 *uint8, x16 *int16, u16 *uint16, x64 *int64, u64 *uint64) bool {
|
||||
|
||||
// ppc64x:-"MOVBZ R\\d+,\\sR\\d+"
|
||||
if uint32(*u8) == val32[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVH R\\d+,\\sR\\d+"
|
||||
if int32(*x16) == sval32[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
if uint32(*u16) == val32[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// Verify the truncates are using the correct sign.
|
||||
// ppc64x:-"MOVWZ R\\d+,\\sR\\d+"
|
||||
if int32(*x64) == sval32[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVW R\\d+,\\sR\\d+"
|
||||
if uint32(*u64) == val32[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func cmp64(u8 *uint8, x16 *int16, u16 *uint16, x32 *int32, u32 *uint32) bool {
|
||||
|
||||
// ppc64x:-"MOVBZ R\\d+,\\sR\\d+"
|
||||
if uint64(*u8) == val64[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVH R\\d+,\\sR\\d+"
|
||||
if int64(*x16) == sval64[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVHZ R\\d+,\\sR\\d+"
|
||||
if uint64(*u16) == val64[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVW R\\d+,\\sR\\d+"
|
||||
if int64(*x32) == sval64[0] {
|
||||
return true
|
||||
}
|
||||
|
||||
// ppc64x:-"MOVWZ R\\d+,\\sR\\d+"
|
||||
if uint64(*u32) == val64[0] {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// no unsign extension following 32 bits ops
|
||||
|
||||
func noUnsignEXT(t1, t2, t3, t4 uint32, k int64) uint64 {
|
||||
var ret uint64
|
||||
|
||||
// arm64:"RORW" -"MOVWU"
|
||||
ret += uint64(bits.RotateLeft32(t1, 7))
|
||||
|
||||
// arm64:"MULW" -"MOVWU"
|
||||
ret *= uint64(t1 * t2)
|
||||
|
||||
// arm64:"MNEGW" -"MOVWU"
|
||||
ret += uint64(-t1 * t3)
|
||||
|
||||
// arm64:"UDIVW" -"MOVWU"
|
||||
ret += uint64(t1 / t4)
|
||||
|
||||
// arm64:-"MOVWU"
|
||||
ret += uint64(t2 % t3)
|
||||
|
||||
// arm64:"MSUBW" -"MOVWU"
|
||||
ret += uint64(t1 - t2*t3)
|
||||
|
||||
// arm64:"MADDW" -"MOVWU"
|
||||
ret += uint64(t3*t4 + t2)
|
||||
|
||||
// arm64:"REVW" -"MOVWU"
|
||||
ret += uint64(bits.ReverseBytes32(t1))
|
||||
|
||||
// arm64:"RBITW" -"MOVWU"
|
||||
ret += uint64(bits.Reverse32(t1))
|
||||
|
||||
// arm64:"CLZW" -"MOVWU"
|
||||
ret += uint64(bits.LeadingZeros32(t1))
|
||||
|
||||
// arm64:"REV16W" -"MOVWU"
|
||||
ret += uint64(((t1 & 0xff00ff00) >> 8) | ((t1 & 0x00ff00ff) << 8))
|
||||
|
||||
// arm64:"EXTRW" -"MOVWU"
|
||||
ret += uint64((t1 << 25) | (t2 >> 7))
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// no sign extension when the upper bits of the result are zero
|
||||
|
||||
func noSignEXT(x int) int64 {
|
||||
t1 := int32(x)
|
||||
|
||||
var ret int64
|
||||
|
||||
// arm64:-"MOVW"
|
||||
ret += int64(t1 & 1)
|
||||
|
||||
// arm64:-"MOVW"
|
||||
ret += int64(int32(x & 0x7fffffff))
|
||||
|
||||
// arm64:-"MOVH"
|
||||
ret += int64(int16(x & 0x7fff))
|
||||
|
||||
// arm64:-"MOVB"
|
||||
ret += int64(int8(x & 0x7f))
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// corner cases that sign extension must not be omitted
|
||||
|
||||
func shouldSignEXT(x int) int64 {
|
||||
t1 := int32(x)
|
||||
|
||||
var ret int64
|
||||
|
||||
// arm64:"MOVW"
|
||||
ret += int64(t1 & (-1))
|
||||
|
||||
// arm64:"MOVW"
|
||||
ret += int64(int32(x & 0x80000000))
|
||||
|
||||
// arm64:"MOVW"
|
||||
ret += int64(int32(x & 0x1100000011111111))
|
||||
|
||||
// arm64:"MOVH"
|
||||
ret += int64(int16(x & 0x1100000000001111))
|
||||
|
||||
// arm64:"MOVB"
|
||||
ret += int64(int8(x & 0x1100000000000011))
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func noIntermediateExtension(a, b, c uint32) uint32 {
|
||||
// arm64:-"MOVWU"
|
||||
return a*b*9 + c
|
||||
}
|
||||
22
test/codegen/race.go
Normal file
22
test/codegen/race.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// asmcheck -race
|
||||
|
||||
// Copyright 2019 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
|
||||
|
||||
// Check that we elide racefuncenter/racefuncexit for
|
||||
// functions with no calls (but which might panic
|
||||
// in various ways). See issue 31219.
|
||||
// amd64:-"CALL.*racefuncenter.*"
|
||||
// arm64:-"CALL.*racefuncenter.*"
|
||||
// ppc64le:-"CALL.*racefuncenter.*"
|
||||
func RaceMightPanic(a []int, i, j, k, s int) {
|
||||
var b [4]int
|
||||
_ = b[i] // panicIndex
|
||||
_ = a[i:j] // panicSlice
|
||||
_ = a[i:j:k] // also panicSlice
|
||||
_ = i << s // panicShift
|
||||
_ = i / j // panicDivide
|
||||
}
|
||||
21
test/codegen/reflect_type.go
Normal file
21
test/codegen/reflect_type.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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 "reflect"
|
||||
|
||||
func intPtrTypeSize() uintptr {
|
||||
// amd64:"MOVL [$]8," -"CALL"
|
||||
// arm64:"MOVD [$]8," -"CALL"
|
||||
return reflect.TypeFor[*int]().Size()
|
||||
}
|
||||
|
||||
func intPtrTypeKind() reflect.Kind {
|
||||
// amd64:"MOVL [$]22," -"CALL"
|
||||
// arm64:"MOVD [$]22," -"CALL"
|
||||
return reflect.TypeFor[*int]().Kind()
|
||||
}
|
||||
23
test/codegen/regabi_regalloc.go
Normal file
23
test/codegen/regabi_regalloc.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2021 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
|
||||
|
||||
//go:registerparams
|
||||
func f1(a, b int) {
|
||||
// amd64:"MOVQ BX, CX", "MOVQ AX, BX", "MOVL [$]1, AX", -"MOVQ .*DX"
|
||||
g(1, a, b)
|
||||
}
|
||||
|
||||
//go:registerparams
|
||||
func f2(a, b int) {
|
||||
// amd64:"MOVQ BX, AX", "MOVQ [AB]X, CX", -"MOVQ .*, BX"
|
||||
g(b, b, b)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
//go:registerparams
|
||||
func g(int, int, int) {}
|
||||
43
test/codegen/retpoline.go
Normal file
43
test/codegen/retpoline.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// asmcheck -gcflags=-spectre=ret
|
||||
|
||||
//go:build amd64
|
||||
|
||||
package codegen
|
||||
|
||||
func CallFunc(f func()) {
|
||||
// amd64:`CALL runtime.retpoline`
|
||||
f()
|
||||
}
|
||||
|
||||
func CallInterface(x interface{ M() }) {
|
||||
// amd64:`CALL runtime.retpoline`
|
||||
x.M()
|
||||
}
|
||||
|
||||
// Check to make sure that jump tables are disabled
|
||||
// when retpoline is on. See issue 57097.
|
||||
func noJumpTables(x int) int {
|
||||
switch x {
|
||||
case 0:
|
||||
return 0
|
||||
case 1:
|
||||
return 1
|
||||
case 2:
|
||||
return 2
|
||||
case 3:
|
||||
return 3
|
||||
case 4:
|
||||
return 4
|
||||
case 5:
|
||||
return 5
|
||||
case 6:
|
||||
return 6
|
||||
case 7:
|
||||
return 7
|
||||
case 8:
|
||||
return 8
|
||||
case 9:
|
||||
return 9
|
||||
}
|
||||
return 10
|
||||
}
|
||||
281
test/codegen/rotate.go
Normal file
281
test/codegen/rotate.go
Normal file
@@ -0,0 +1,281 @@
|
||||
// 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 "math/bits"
|
||||
|
||||
// ------------------- //
|
||||
// const rotates //
|
||||
// ------------------- //
|
||||
|
||||
func rot64(x uint64) uint64 {
|
||||
var a uint64
|
||||
|
||||
// amd64:"ROLQ [$]7"
|
||||
// ppc64x:"ROTL [$]7"
|
||||
// loong64: "ROTRV [$]57"
|
||||
// riscv64: "RORI [$]57"
|
||||
a += x<<7 | x>>57
|
||||
|
||||
// amd64:"ROLQ [$]8"
|
||||
// arm64:"ROR [$]56"
|
||||
// s390x:"RISBGZ [$]0, [$]63, [$]8, "
|
||||
// ppc64x:"ROTL [$]8"
|
||||
// loong64: "ROTRV [$]56"
|
||||
// riscv64: "RORI [$]56"
|
||||
a += x<<8 + x>>56
|
||||
|
||||
// amd64:"ROLQ [$]9"
|
||||
// arm64:"ROR [$]55"
|
||||
// s390x:"RISBGZ [$]0, [$]63, [$]9, "
|
||||
// ppc64x:"ROTL [$]9"
|
||||
// loong64: "ROTRV [$]55"
|
||||
// riscv64: "RORI [$]55"
|
||||
a += x<<9 ^ x>>55
|
||||
|
||||
// amd64:"ROLQ [$]10"
|
||||
// arm64:"ROR [$]54"
|
||||
// s390x:"RISBGZ [$]0, [$]63, [$]10, "
|
||||
// ppc64x:"ROTL [$]10"
|
||||
// arm64:"ROR [$]54"
|
||||
// s390x:"RISBGZ [$]0, [$]63, [$]10, "
|
||||
// loong64: "ROTRV [$]54"
|
||||
// riscv64: "RORI [$]54"
|
||||
a += bits.RotateLeft64(x, 10)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func rot32(x uint32) uint32 {
|
||||
var a uint32
|
||||
|
||||
// amd64:"ROLL [$]7"
|
||||
// arm:"MOVW R\\d+@>25"
|
||||
// ppc64x:"ROTLW [$]7"
|
||||
// loong64: "ROTR [$]25"
|
||||
// riscv64: "RORIW [$]25"
|
||||
a += x<<7 | x>>25
|
||||
|
||||
// amd64:`ROLL [$]8`
|
||||
// arm:"MOVW R\\d+@>24"
|
||||
// arm64:"RORW [$]24"
|
||||
// s390x:"RLL [$]8"
|
||||
// ppc64x:"ROTLW [$]8"
|
||||
// loong64: "ROTR [$]24"
|
||||
// riscv64: "RORIW [$]24"
|
||||
a += x<<8 + x>>24
|
||||
|
||||
// amd64:"ROLL [$]9"
|
||||
// arm:"MOVW R\\d+@>23"
|
||||
// arm64:"RORW [$]23"
|
||||
// s390x:"RLL [$]9"
|
||||
// ppc64x:"ROTLW [$]9"
|
||||
// loong64: "ROTR [$]23"
|
||||
// riscv64: "RORIW [$]23"
|
||||
a += x<<9 ^ x>>23
|
||||
|
||||
// amd64:"ROLL [$]10"
|
||||
// arm:"MOVW R\\d+@>22"
|
||||
// arm64:"RORW [$]22"
|
||||
// s390x:"RLL [$]10"
|
||||
// ppc64x:"ROTLW [$]10"
|
||||
// arm64:"RORW [$]22"
|
||||
// s390x:"RLL [$]10"
|
||||
// loong64: "ROTR [$]22"
|
||||
// riscv64: "RORIW [$]22"
|
||||
a += bits.RotateLeft32(x, 10)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func rot16(x uint16) uint16 {
|
||||
var a uint16
|
||||
|
||||
// amd64:"ROLW [$]7"
|
||||
// riscv64: "OR" "SLLI" "SRLI" -"AND"
|
||||
a += x<<7 | x>>9
|
||||
|
||||
// amd64:`ROLW [$]8`
|
||||
// riscv64: "OR" "SLLI" "SRLI" -"AND"
|
||||
a += x<<8 + x>>8
|
||||
|
||||
// amd64:"ROLW [$]9"
|
||||
// riscv64: "OR" "SLLI" "SRLI" -"AND"
|
||||
a += x<<9 ^ x>>7
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func rot8(x uint8) uint8 {
|
||||
var a uint8
|
||||
|
||||
// amd64:"ROLB [$]5"
|
||||
// riscv64: "OR" "SLLI" "SRLI" -"AND"
|
||||
a += x<<5 | x>>3
|
||||
|
||||
// amd64:`ROLB [$]6`
|
||||
// riscv64: "OR" "SLLI" "SRLI" -"AND"
|
||||
a += x<<6 + x>>2
|
||||
|
||||
// amd64:"ROLB [$]7"
|
||||
// riscv64: "OR" "SLLI" "SRLI" -"AND"
|
||||
a += x<<7 ^ x>>1
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// ----------------------- //
|
||||
// non-const rotates //
|
||||
// ----------------------- //
|
||||
|
||||
func rot64nc(x uint64, z uint) uint64 {
|
||||
var a uint64
|
||||
|
||||
z &= 63
|
||||
|
||||
// amd64:"ROLQ" -"AND"
|
||||
// arm64:"ROR" "NEG" -"AND"
|
||||
// ppc64x:"ROTL" -"NEG" -"AND"
|
||||
// loong64: "ROTRV", -"AND"
|
||||
// riscv64: "ROL" -"AND"
|
||||
a += x<<z | x>>(64-z)
|
||||
|
||||
// amd64:"RORQ" -"AND"
|
||||
// arm64:"ROR" -"NEG" -"AND"
|
||||
// ppc64x:"ROTL" "NEG" -"AND"
|
||||
// loong64: "ROTRV", -"AND"
|
||||
// riscv64: "ROR" -"AND"
|
||||
a += x>>z | x<<(64-z)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func rot32nc(x uint32, z uint) uint32 {
|
||||
var a uint32
|
||||
|
||||
z &= 31
|
||||
|
||||
// amd64:"ROLL" -"AND"
|
||||
// arm64:"ROR" "NEG" -"AND"
|
||||
// ppc64x:"ROTLW" -"NEG" -"AND"
|
||||
// loong64: "ROTR", -"AND"
|
||||
// riscv64: "ROLW" -"AND"
|
||||
a += x<<z | x>>(32-z)
|
||||
|
||||
// amd64:"RORL" -"AND"
|
||||
// arm64:"ROR" -"NEG" -"AND"
|
||||
// ppc64x:"ROTLW" "NEG" -"AND"
|
||||
// loong64: "ROTR", -"AND"
|
||||
// riscv64: "RORW" -"AND"
|
||||
a += x>>z | x<<(32-z)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func rot16nc(x uint16, z uint) uint16 {
|
||||
var a uint16
|
||||
|
||||
z &= 15
|
||||
|
||||
// amd64:"ROLW" -"ANDQ"
|
||||
// riscv64: "OR" "SLL" "SRL" -"AND "
|
||||
a += x<<z | x>>(16-z)
|
||||
|
||||
// amd64:"RORW" -"ANDQ"
|
||||
// riscv64: "OR" "SLL" "SRL" -"AND "
|
||||
a += x>>z | x<<(16-z)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func rot8nc(x uint8, z uint) uint8 {
|
||||
var a uint8
|
||||
|
||||
z &= 7
|
||||
|
||||
// amd64:"ROLB" -"ANDQ"
|
||||
// riscv64: "OR" "SLL" "SRL" -"AND "
|
||||
a += x<<z | x>>(8-z)
|
||||
|
||||
// amd64:"RORB" -"ANDQ"
|
||||
// riscv64: "OR" "SLL" "SRL" -"AND "
|
||||
a += x>>z | x<<(8-z)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// Issue 18254: rotate after inlining
|
||||
func f32(x uint32) uint32 {
|
||||
// amd64:"ROLL [$]7"
|
||||
return rot32nc(x, 7)
|
||||
}
|
||||
|
||||
func doubleRotate(x uint64) uint64 {
|
||||
x = (x << 5) | (x >> 59)
|
||||
// amd64:"ROLQ [$]15"
|
||||
// arm64:"ROR [$]49"
|
||||
x = (x << 10) | (x >> 54)
|
||||
return x
|
||||
}
|
||||
|
||||
// --------------------------------------- //
|
||||
// Combined Rotate + Masking operations //
|
||||
// --------------------------------------- //
|
||||
|
||||
func checkMaskedRotate32(a []uint32, r int) {
|
||||
i := 0
|
||||
|
||||
// ppc64x: "RLWNM [$]16, R[0-9]+, [$]8, [$]15, R[0-9]+"
|
||||
a[i] = bits.RotateLeft32(a[i], 16) & 0xFF0000
|
||||
i++
|
||||
// ppc64x: "RLWNM [$]16, R[0-9]+, [$]8, [$]15, R[0-9]+"
|
||||
a[i] = bits.RotateLeft32(a[i]&0xFF, 16)
|
||||
i++
|
||||
// ppc64x: "RLWNM [$]4, R[0-9]+, [$]20, [$]27, R[0-9]+"
|
||||
a[i] = bits.RotateLeft32(a[i], 4) & 0xFF0
|
||||
i++
|
||||
// ppc64x: "RLWNM [$]16, R[0-9]+, [$]24, [$]31, R[0-9]+"
|
||||
a[i] = bits.RotateLeft32(a[i]&0xFF0000, 16)
|
||||
i++
|
||||
|
||||
// ppc64x: "RLWNM R[0-9]+, R[0-9]+, [$]8, [$]15, R[0-9]+"
|
||||
a[i] = bits.RotateLeft32(a[i], r) & 0xFF0000
|
||||
i++
|
||||
// ppc64x: "RLWNM R[0-9]+, R[0-9]+, [$]16, [$]23, R[0-9]+"
|
||||
a[i] = bits.RotateLeft32(a[i], r) & 0xFF00
|
||||
i++
|
||||
|
||||
// ppc64x: "RLWNM R[0-9]+, R[0-9]+, [$]20, [$]11, R[0-9]+"
|
||||
a[i] = bits.RotateLeft32(a[i], r) & 0xFFF00FFF
|
||||
i++
|
||||
// ppc64x: "RLWNM [$]4, R[0-9]+, [$]20, [$]11, R[0-9]+"
|
||||
a[i] = bits.RotateLeft32(a[i], 4) & 0xFFF00FFF
|
||||
i++
|
||||
}
|
||||
|
||||
// combined arithmetic and rotate on arm64
|
||||
func checkArithmeticWithRotate(a *[1000]uint64) {
|
||||
// arm64: "AND R[0-9]+@>51, R[0-9]+, R[0-9]+"
|
||||
a[2] = a[1] & bits.RotateLeft64(a[0], 13)
|
||||
// arm64: "ORR R[0-9]+@>51, R[0-9]+, R[0-9]+"
|
||||
a[5] = a[4] | bits.RotateLeft64(a[3], 13)
|
||||
// arm64: "EOR R[0-9]+@>51, R[0-9]+, R[0-9]+"
|
||||
a[8] = a[7] ^ bits.RotateLeft64(a[6], 13)
|
||||
// arm64: "MVN R[0-9]+@>51, R[0-9]+"
|
||||
a[10] = ^bits.RotateLeft64(a[9], 13)
|
||||
// arm64: "BIC R[0-9]+@>51, R[0-9]+, R[0-9]+"
|
||||
a[13] = a[12] &^ bits.RotateLeft64(a[11], 13)
|
||||
// arm64: "EON R[0-9]+@>51, R[0-9]+, R[0-9]+"
|
||||
a[16] = a[15] ^ ^bits.RotateLeft64(a[14], 13)
|
||||
// arm64: "ORN R[0-9]+@>51, R[0-9]+, R[0-9]+"
|
||||
a[19] = a[18] | ^bits.RotateLeft64(a[17], 13)
|
||||
// arm64: "TST R[0-9]+@>51, R[0-9]+"
|
||||
if a[18]&bits.RotateLeft64(a[19], 13) == 0 {
|
||||
a[20] = 1
|
||||
}
|
||||
|
||||
}
|
||||
17
test/codegen/schedule.go
Normal file
17
test/codegen/schedule.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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
|
||||
|
||||
func f(n int) int {
|
||||
r := 0
|
||||
// arm64:-"MOVD R"
|
||||
// amd64:-"LEAQ" "INCQ"
|
||||
for i := range n {
|
||||
r += i
|
||||
}
|
||||
return r
|
||||
}
|
||||
20
test/codegen/select.go
Normal file
20
test/codegen/select.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2020 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
|
||||
|
||||
func f() {
|
||||
ch1 := make(chan int)
|
||||
ch2 := make(chan int)
|
||||
for {
|
||||
// amd64:-`MOVQ [$]0, command-line-arguments..autotmp_3`
|
||||
select {
|
||||
case <-ch1:
|
||||
case <-ch2:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
697
test/codegen/shift.go
Normal file
697
test/codegen/shift.go
Normal file
@@ -0,0 +1,697 @@
|
||||
// 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
|
||||
|
||||
// ------------------ //
|
||||
// constant shifts //
|
||||
// ------------------ //
|
||||
|
||||
func lshConst64x64(v int64) int64 {
|
||||
// loong64:"SLLV"
|
||||
// ppc64x:"SLD"
|
||||
// riscv64:"SLLI" -"AND" -"SLTIU"
|
||||
return v << uint64(33)
|
||||
}
|
||||
|
||||
func rshConst64Ux64(v uint64) uint64 {
|
||||
// loong64:"SRLV"
|
||||
// ppc64x:"SRD"
|
||||
// riscv64:"SRLI " -"AND" -"SLTIU"
|
||||
return v >> uint64(33)
|
||||
}
|
||||
|
||||
func rshConst64Ux64Overflow32(v uint32) uint64 {
|
||||
// loong64:"MOVV R0," -"SRL "
|
||||
// riscv64:"MOV [$]0," -"SRL"
|
||||
return uint64(v) >> 32
|
||||
}
|
||||
|
||||
func rshConst64Ux64Overflow16(v uint16) uint64 {
|
||||
// loong64:"MOVV R0," -"SRLV"
|
||||
// riscv64:"MOV [$]0," -"SRL"
|
||||
return uint64(v) >> 16
|
||||
}
|
||||
|
||||
func rshConst64Ux64Overflow8(v uint8) uint64 {
|
||||
// loong64:"MOVV R0," -"SRLV"
|
||||
// riscv64:"MOV [$]0," -"SRL"
|
||||
return uint64(v) >> 8
|
||||
}
|
||||
|
||||
func rshConst64x64(v int64) int64 {
|
||||
// loong64:"SRAV"
|
||||
// ppc64x:"SRAD"
|
||||
// riscv64:"SRAI " -"OR" -"SLTIU"
|
||||
return v >> uint64(33)
|
||||
}
|
||||
|
||||
func rshConst64x64Overflow32(v int32) int64 {
|
||||
// loong64:"SRA [$]31"
|
||||
// riscv64:"SRAIW" -"SLLI" -"SRAI "
|
||||
return int64(v) >> 32
|
||||
}
|
||||
|
||||
func rshConst64x64Overflow16(v int16) int64 {
|
||||
// loong64:"SLLV [$]48" "SRAV [$]63"
|
||||
// riscv64:"SLLI" "SRAI" -"SRAIW"
|
||||
return int64(v) >> 16
|
||||
}
|
||||
|
||||
func rshConst64x64Overflow8(v int8) int64 {
|
||||
// loong64:"SLLV [$]56" "SRAV [$]63"
|
||||
// riscv64:"SLLI" "SRAI" -"SRAIW"
|
||||
return int64(v) >> 8
|
||||
}
|
||||
|
||||
func lshConst32x1(v int32) int32 {
|
||||
// amd64:"ADDL", -"SHLL"
|
||||
return v << 1
|
||||
}
|
||||
|
||||
func lshConst64x1(v int64) int64 {
|
||||
// amd64:"ADDQ", -"SHLQ"
|
||||
return v << 1
|
||||
}
|
||||
|
||||
func lshConst32x64(v int32) int32 {
|
||||
// loong64:"SLL "
|
||||
// ppc64x:"SLW"
|
||||
// riscv64:"SLLI" -"AND" -"SLTIU", -"MOVW"
|
||||
return v << uint64(29)
|
||||
}
|
||||
|
||||
func rshConst32Ux64(v uint32) uint32 {
|
||||
// loong64:"SRL "
|
||||
// ppc64x:"SRW"
|
||||
// riscv64:"SRLIW" -"AND" -"SLTIU", -"MOVW"
|
||||
return v >> uint64(29)
|
||||
}
|
||||
|
||||
func rshConst32x64(v int32) int32 {
|
||||
// loong64:"SRA "
|
||||
// ppc64x:"SRAW"
|
||||
// riscv64:"SRAIW" -"OR" -"SLTIU", -"MOVW"
|
||||
return v >> uint64(29)
|
||||
}
|
||||
|
||||
func lshConst64x32(v int64) int64 {
|
||||
// loong64:"SLLV"
|
||||
// ppc64x:"SLD"
|
||||
// riscv64:"SLLI" -"AND" -"SLTIU"
|
||||
return v << uint32(33)
|
||||
}
|
||||
|
||||
func rshConst64Ux32(v uint64) uint64 {
|
||||
// loong64:"SRLV"
|
||||
// ppc64x:"SRD"
|
||||
// riscv64:"SRLI " -"AND" -"SLTIU"
|
||||
return v >> uint32(33)
|
||||
}
|
||||
|
||||
func rshConst64x32(v int64) int64 {
|
||||
// loong64:"SRAV"
|
||||
// ppc64x:"SRAD"
|
||||
// riscv64:"SRAI " -"OR" -"SLTIU"
|
||||
return v >> uint32(33)
|
||||
}
|
||||
|
||||
func lshConst32x1Add(x int32) int32 {
|
||||
// amd64:"SHLL [$]2"
|
||||
// loong64:"SLL [$]2"
|
||||
// riscv64:"SLLI [$]2"
|
||||
return (x + x) << 1
|
||||
}
|
||||
|
||||
func lshConst64x1Add(x int64) int64 {
|
||||
// amd64:"SHLQ [$]2"
|
||||
// loong64:"SLLV [$]2"
|
||||
// riscv64:"SLLI [$]2"
|
||||
return (x + x) << 1
|
||||
}
|
||||
|
||||
func lshConst32x2Add(x int32) int32 {
|
||||
// amd64:"SHLL [$]3"
|
||||
// loong64:"SLL [$]3"
|
||||
// riscv64:"SLLI [$]3"
|
||||
return (x + x) << 2
|
||||
}
|
||||
|
||||
func lshConst64x2Add(x int64) int64 {
|
||||
// amd64:"SHLQ [$]3"
|
||||
// loong64:"SLLV [$]3"
|
||||
// riscv64:"SLLI [$]3"
|
||||
return (x + x) << 2
|
||||
}
|
||||
|
||||
func lshConst32x31Add(x int32) int32 {
|
||||
// loong64:-"SLL " "MOVV R0"
|
||||
// riscv64:-"SLLI" "MOV [$]0"
|
||||
return (x + x) << 31
|
||||
}
|
||||
|
||||
func lshConst64x63Add(x int64) int64 {
|
||||
// loong64:-"SLLV" "MOVV R0"
|
||||
// riscv64:-"SLLI" "MOV [$]0"
|
||||
return (x + x) << 63
|
||||
}
|
||||
|
||||
// ------------------ //
|
||||
// masked shifts //
|
||||
// ------------------ //
|
||||
|
||||
func lshMask64x64(v int64, s uint64) int64 {
|
||||
// arm64:"LSL" -"AND"
|
||||
// loong64:"SLLV" -"AND"
|
||||
// ppc64x:"RLDICL" -"ORN" -"ISEL"
|
||||
// riscv64:"SLL" -"AND " -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v << (s & 63)
|
||||
}
|
||||
|
||||
func rshMask64Ux64(v uint64, s uint64) uint64 {
|
||||
// arm64:"LSR" -"AND" -"CSEL"
|
||||
// loong64:"SRLV" -"AND"
|
||||
// ppc64x:"RLDICL" -"ORN" -"ISEL"
|
||||
// riscv64:"SRL " -"AND " -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v >> (s & 63)
|
||||
}
|
||||
|
||||
func rshMask64x64(v int64, s uint64) int64 {
|
||||
// arm64:"ASR" -"AND" -"CSEL"
|
||||
// loong64:"SRAV" -"AND"
|
||||
// ppc64x:"RLDICL" -"ORN" -"ISEL"
|
||||
// riscv64:"SRA " -"OR" -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v >> (s & 63)
|
||||
}
|
||||
|
||||
func lshMask32x64(v int32, s uint64) int32 {
|
||||
// arm64:"LSL" -"AND"
|
||||
// loong64:"SLL " "AND" "SGTU" "MASKEQZ"
|
||||
// ppc64x:"ISEL" -"ORN"
|
||||
// riscv64:"SLL" -"AND " -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v << (s & 63)
|
||||
}
|
||||
|
||||
func lsh5Mask32x64(v int32, s uint64) int32 {
|
||||
// loong64:"SLL " -"AND"
|
||||
return v << (s & 31)
|
||||
}
|
||||
|
||||
func rshMask32Ux64(v uint32, s uint64) uint32 {
|
||||
// arm64:"LSR" -"AND"
|
||||
// loong64:"SRL " "AND" "SGTU" "MASKEQZ"
|
||||
// ppc64x:"ISEL" -"ORN"
|
||||
// riscv64:"SRLW" "SLTIU" "NEG" "AND " -"SRL "
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v >> (s & 63)
|
||||
}
|
||||
|
||||
func rsh5Mask32Ux64(v uint32, s uint64) uint32 {
|
||||
// loong64:"SRL " -"AND"
|
||||
// riscv64:"SRLW" -"AND " -"SLTIU" -"SRL "
|
||||
return v >> (s & 31)
|
||||
}
|
||||
|
||||
func rshMask32x64(v int32, s uint64) int32 {
|
||||
// arm64:"ASR" -"AND"
|
||||
// loong64:"SRA " "AND" "SGTU" "SUBVU" "OR"
|
||||
// ppc64x:"ISEL" -"ORN"
|
||||
// riscv64:"SRAW" "OR" "SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v >> (s & 63)
|
||||
}
|
||||
|
||||
func rsh5Mask32x64(v int32, s uint64) int32 {
|
||||
// loong64:"SRA " -"AND"
|
||||
// riscv64:"SRAW" -"OR" -"SLTIU"
|
||||
return v >> (s & 31)
|
||||
}
|
||||
|
||||
func lshMask64x32(v int64, s uint32) int64 {
|
||||
// arm64:"LSL" -"AND"
|
||||
// loong64:"SLLV" -"AND"
|
||||
// ppc64x:"RLDICL" -"ORN"
|
||||
// riscv64:"SLL" -"AND " -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v << (s & 63)
|
||||
}
|
||||
|
||||
func rshMask64Ux32(v uint64, s uint32) uint64 {
|
||||
// arm64:"LSR" -"AND" -"CSEL"
|
||||
// loong64:"SRLV" -"AND"
|
||||
// ppc64x:"RLDICL" -"ORN"
|
||||
// riscv64:"SRL " -"AND " -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v >> (s & 63)
|
||||
}
|
||||
|
||||
func rshMask64x32(v int64, s uint32) int64 {
|
||||
// arm64:"ASR" -"AND" -"CSEL"
|
||||
// loong64:"SRAV" -"AND"
|
||||
// ppc64x:"RLDICL" -"ORN" -"ISEL"
|
||||
// riscv64:"SRA " -"OR" -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v >> (s & 63)
|
||||
}
|
||||
|
||||
func lshMask64x32Ext(v int64, s int32) int64 {
|
||||
// ppc64x:"RLDICL" -"ORN" -"ISEL"
|
||||
// riscv64:"SLL" -"AND " -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v << uint(s&63)
|
||||
}
|
||||
|
||||
func rshMask64Ux32Ext(v uint64, s int32) uint64 {
|
||||
// ppc64x:"RLDICL" -"ORN" -"ISEL"
|
||||
// riscv64:"SRL " -"AND " -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v >> uint(s&63)
|
||||
}
|
||||
|
||||
func rshMask64x32Ext(v int64, s int32) int64 {
|
||||
// ppc64x:"RLDICL" -"ORN" -"ISEL"
|
||||
// riscv64:"SRA " -"OR" -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
return v >> uint(s&63)
|
||||
}
|
||||
|
||||
// --------------- //
|
||||
// signed shifts //
|
||||
// --------------- //
|
||||
|
||||
// We do want to generate a test + panicshift for these cases.
|
||||
func lshSigned(v8 int8, v16 int16, v32 int32, v64 int64, x int) {
|
||||
// amd64:"TESTB"
|
||||
_ = x << v8
|
||||
// amd64:"TESTW"
|
||||
_ = x << v16
|
||||
// amd64:"TESTL"
|
||||
_ = x << v32
|
||||
// amd64:"TESTQ"
|
||||
_ = x << v64
|
||||
}
|
||||
|
||||
// We want to avoid generating a test + panicshift for these cases.
|
||||
func lshSignedMasked(v8 int8, v16 int16, v32 int32, v64 int64, x int) {
|
||||
// amd64:-"TESTB"
|
||||
_ = x << (v8 & 7)
|
||||
// amd64:-"TESTW"
|
||||
_ = x << (v16 & 15)
|
||||
// amd64:-"TESTL"
|
||||
_ = x << (v32 & 31)
|
||||
// amd64:-"TESTQ"
|
||||
_ = x << (v64 & 63)
|
||||
}
|
||||
|
||||
// ------------------ //
|
||||
// bounded shifts //
|
||||
// ------------------ //
|
||||
|
||||
func lshGuarded64(v int64, s uint) int64 {
|
||||
if s < 64 {
|
||||
// riscv64:"SLL" -"AND" -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
// wasm:-"Select" -".*LtU"
|
||||
// arm64:"LSL" -"CSEL"
|
||||
return v << s
|
||||
}
|
||||
panic("shift too large")
|
||||
}
|
||||
|
||||
func rshGuarded64U(v uint64, s uint) uint64 {
|
||||
if s < 64 {
|
||||
// riscv64:"SRL " -"AND" -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
// wasm:-"Select" -".*LtU"
|
||||
// arm64:"LSR" -"CSEL"
|
||||
return v >> s
|
||||
}
|
||||
panic("shift too large")
|
||||
}
|
||||
|
||||
func rshGuarded64(v int64, s uint) int64 {
|
||||
if s < 64 {
|
||||
// riscv64:"SRA " -"OR" -"SLTIU"
|
||||
// s390x:-"RISBGZ" -"AND" -"LOCGR"
|
||||
// wasm:-"Select" -".*LtU"
|
||||
// arm64:"ASR" -"CSEL"
|
||||
return v >> s
|
||||
}
|
||||
panic("shift too large")
|
||||
}
|
||||
|
||||
func provedUnsignedShiftLeft(val64 uint64, val32 uint32, val16 uint16, val8 uint8, shift int) (r1 uint64, r2 uint32, r3 uint16, r4 uint8) {
|
||||
if shift >= 0 && shift < 64 {
|
||||
// arm64:"LSL" -"CSEL"
|
||||
r1 = val64 << shift
|
||||
}
|
||||
if shift >= 0 && shift < 32 {
|
||||
// arm64:"LSL" -"CSEL"
|
||||
r2 = val32 << shift
|
||||
}
|
||||
if shift >= 0 && shift < 16 {
|
||||
// arm64:"LSL" -"CSEL"
|
||||
r3 = val16 << shift
|
||||
}
|
||||
if shift >= 0 && shift < 8 {
|
||||
// arm64:"LSL" -"CSEL"
|
||||
r4 = val8 << shift
|
||||
}
|
||||
return r1, r2, r3, r4
|
||||
}
|
||||
|
||||
func provedSignedShiftLeft(val64 int64, val32 int32, val16 int16, val8 int8, shift int) (r1 int64, r2 int32, r3 int16, r4 int8) {
|
||||
if shift >= 0 && shift < 64 {
|
||||
// arm64:"LSL" -"CSEL"
|
||||
r1 = val64 << shift
|
||||
}
|
||||
if shift >= 0 && shift < 32 {
|
||||
// arm64:"LSL" -"CSEL"
|
||||
r2 = val32 << shift
|
||||
}
|
||||
if shift >= 0 && shift < 16 {
|
||||
// arm64:"LSL" -"CSEL"
|
||||
r3 = val16 << shift
|
||||
}
|
||||
if shift >= 0 && shift < 8 {
|
||||
// arm64:"LSL" -"CSEL"
|
||||
r4 = val8 << shift
|
||||
}
|
||||
return r1, r2, r3, r4
|
||||
}
|
||||
|
||||
func provedUnsignedShiftRight(val64 uint64, val32 uint32, val16 uint16, val8 uint8, shift int) (r1 uint64, r2 uint32, r3 uint16, r4 uint8) {
|
||||
if shift >= 0 && shift < 64 {
|
||||
// arm64:"LSR" -"CSEL"
|
||||
r1 = val64 >> shift
|
||||
}
|
||||
if shift >= 0 && shift < 32 {
|
||||
// arm64:"LSR" -"CSEL"
|
||||
r2 = val32 >> shift
|
||||
}
|
||||
if shift >= 0 && shift < 16 {
|
||||
// arm64:"LSR" -"CSEL"
|
||||
r3 = val16 >> shift
|
||||
}
|
||||
if shift >= 0 && shift < 8 {
|
||||
// arm64:"LSR" -"CSEL"
|
||||
r4 = val8 >> shift
|
||||
}
|
||||
return r1, r2, r3, r4
|
||||
}
|
||||
|
||||
func provedSignedShiftRight(val64 int64, val32 int32, val16 int16, val8 int8, shift int) (r1 int64, r2 int32, r3 int16, r4 int8) {
|
||||
if shift >= 0 && shift < 64 {
|
||||
// arm64:"ASR" -"CSEL"
|
||||
r1 = val64 >> shift
|
||||
}
|
||||
if shift >= 0 && shift < 32 {
|
||||
// arm64:"ASR" -"CSEL"
|
||||
r2 = val32 >> shift
|
||||
}
|
||||
if shift >= 0 && shift < 16 {
|
||||
// arm64:"ASR" -"CSEL"
|
||||
r3 = val16 >> shift
|
||||
}
|
||||
if shift >= 0 && shift < 8 {
|
||||
// arm64:"ASR" -"CSEL"
|
||||
r4 = val8 >> shift
|
||||
}
|
||||
return r1, r2, r3, r4
|
||||
}
|
||||
|
||||
func checkUnneededTrunc(tab *[100000]uint32, d uint64, v uint32, h uint16, b byte) (uint32, uint64) {
|
||||
|
||||
// ppc64x:-".*RLWINM" -".*RLDICR" ".*CLRLSLDI"
|
||||
f := tab[byte(v)^b]
|
||||
// ppc64x:-".*RLWINM" -".*RLDICR" ".*CLRLSLDI"
|
||||
f += tab[byte(v)&b]
|
||||
// ppc64x:-".*RLWINM" -".*RLDICR" ".*CLRLSLDI"
|
||||
f += tab[byte(v)|b]
|
||||
// ppc64x:-".*RLWINM" -".*RLDICR" ".*CLRLSLDI"
|
||||
f += tab[uint16(v)&h]
|
||||
// ppc64x:-".*RLWINM" -".*RLDICR" ".*CLRLSLDI"
|
||||
f += tab[uint16(v)^h]
|
||||
// ppc64x:-".*RLWINM" -".*RLDICR" ".*CLRLSLDI"
|
||||
f += tab[uint16(v)|h]
|
||||
// ppc64x:-".*AND" -"RLDICR" ".*CLRLSLDI"
|
||||
f += tab[v&0xff]
|
||||
// ppc64x:-".*AND" ".*CLRLSLWI"
|
||||
f += 2 * uint32(uint16(d))
|
||||
// ppc64x:-".*AND" -"RLDICR" ".*CLRLSLDI"
|
||||
g := 2 * uint64(uint32(d))
|
||||
return f, g
|
||||
}
|
||||
|
||||
func checkCombinedShifts(v8 uint8, v16 uint16, v32 uint32, x32 int32, v64 uint64) (uint8, uint16, uint32, uint64, int64) {
|
||||
|
||||
// ppc64x:-"AND" "CLRLSLWI"
|
||||
f := (v8 & 0xF) << 2
|
||||
// ppc64x:"CLRLSLWI"
|
||||
f += byte(v16) << 3
|
||||
// ppc64x:-"AND" "CLRLSLWI"
|
||||
g := (v16 & 0xFF) << 3
|
||||
// ppc64x:-"AND" "CLRLSLWI"
|
||||
h := (v32 & 0xFFFFF) << 2
|
||||
// ppc64x:"CLRLSLDI"
|
||||
i := (v64 & 0xFFFFFFFF) << 5
|
||||
// ppc64x:-"CLRLSLDI"
|
||||
i += (v64 & 0xFFFFFFF) << 38
|
||||
// ppc64x/power9:-"CLRLSLDI"
|
||||
i += (v64 & 0xFFFF00) << 10
|
||||
// ppc64x/power9:-"SLD" "EXTSWSLI"
|
||||
j := int64(x32+32) * 8
|
||||
return f, g, h, i, j
|
||||
}
|
||||
|
||||
func checkWidenAfterShift(v int64, u uint64) (int64, uint64) {
|
||||
|
||||
// ppc64x:-".*MOVW"
|
||||
f := int32(v >> 32)
|
||||
// ppc64x:".*MOVW"
|
||||
f += int32(v >> 31)
|
||||
// ppc64x:-".*MOVH"
|
||||
g := int16(v >> 48)
|
||||
// ppc64x:".*MOVH"
|
||||
g += int16(v >> 30)
|
||||
// ppc64x:-".*MOVH"
|
||||
g += int16(f >> 16)
|
||||
// ppc64x:-".*MOVB"
|
||||
h := int8(v >> 56)
|
||||
// ppc64x:".*MOVB"
|
||||
h += int8(v >> 28)
|
||||
// ppc64x:-".*MOVB"
|
||||
h += int8(f >> 24)
|
||||
// ppc64x:".*MOVB"
|
||||
h += int8(f >> 16)
|
||||
return int64(h), uint64(g)
|
||||
}
|
||||
|
||||
func checkShiftAndMask32(v []uint32) {
|
||||
i := 0
|
||||
|
||||
// ppc64x: "RLWNM [$]24, R[0-9]+, [$]12, [$]19, R[0-9]+"
|
||||
v[i] = (v[i] & 0xFF00000) >> 8
|
||||
i++
|
||||
// ppc64x: "RLWNM [$]26, R[0-9]+, [$]22, [$]29, R[0-9]+"
|
||||
v[i] = (v[i] & 0xFF00) >> 6
|
||||
i++
|
||||
// ppc64x: "MOVW R0"
|
||||
v[i] = (v[i] & 0xFF) >> 8
|
||||
i++
|
||||
// ppc64x: "MOVW R0"
|
||||
v[i] = (v[i] & 0xF000000) >> 28
|
||||
i++
|
||||
// ppc64x: "RLWNM [$]26, R[0-9]+, [$]24, [$]31, R[0-9]+"
|
||||
v[i] = (v[i] >> 6) & 0xFF
|
||||
i++
|
||||
// ppc64x: "RLWNM [$]26, R[0-9]+, [$]12, [$]19, R[0-9]+"
|
||||
v[i] = (v[i] >> 6) & 0xFF000
|
||||
i++
|
||||
// ppc64x: "MOVW R0"
|
||||
v[i] = (v[i] >> 20) & 0xFF000
|
||||
i++
|
||||
// ppc64x: "MOVW R0"
|
||||
v[i] = (v[i] >> 24) & 0xFF00
|
||||
i++
|
||||
}
|
||||
|
||||
func checkMergedShifts32(a [256]uint32, b [256]uint64, u uint32, v uint32) {
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM [$]10, R[0-9]+, [$]22, [$]29, R[0-9]+"
|
||||
a[0] = a[uint8(v>>24)]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM [$]11, R[0-9]+, [$]21, [$]28, R[0-9]+"
|
||||
b[0] = b[uint8(v>>24)]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM [$]15, R[0-9]+, [$]21, [$]28, R[0-9]+"
|
||||
b[1] = b[(v>>20)&0xFF]
|
||||
// ppc64x: -"SLD", "RLWNM [$]10, R[0-9]+, [$]22, [$]28, R[0-9]+"
|
||||
b[2] = b[v>>25]
|
||||
}
|
||||
|
||||
func checkMergedShifts64(a [256]uint32, b [256]uint64, c [256]byte, v uint64) {
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM [$]10, R[0-9]+, [$]22, [$]29, R[0-9]+"
|
||||
a[0] = a[uint8(v>>24)]
|
||||
// ppc64x: "SRD", "CLRLSLDI", -"RLWNM"
|
||||
a[1] = a[uint8(v>>25)]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM [$]9, R[0-9]+, [$]23, [$]29, R[0-9]+"
|
||||
a[2] = a[v>>25&0x7F]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM [$]3, R[0-9]+, [$]29, [$]29, R[0-9]+"
|
||||
a[3] = a[(v>>31)&0x01]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM [$]12, R[0-9]+, [$]21, [$]28, R[0-9]+"
|
||||
b[0] = b[uint8(v>>23)]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM [$]15, R[0-9]+, [$]21, [$]28, R[0-9]+"
|
||||
b[1] = b[(v>>20)&0xFF]
|
||||
// ppc64x: "RLWNM", -"SLD"
|
||||
b[2] = b[((uint64((uint32(v) >> 21)) & 0x3f) << 4)]
|
||||
// ppc64x: -"RLWNM"
|
||||
b[3] = (b[3] << 24) & 0xFFFFFF000000
|
||||
// ppc64x: "RLWNM [$]24, R[0-9]+, [$]0, [$]7,"
|
||||
b[4] = (b[4] << 24) & 0xFF000000
|
||||
// ppc64x: "RLWNM [$]24, R[0-9]+, [$]0, [$]7,"
|
||||
b[5] = (b[5] << 24) & 0xFF00000F
|
||||
// ppc64x: -"RLWNM"
|
||||
b[6] = (b[6] << 0) & 0xFF00000F
|
||||
// ppc64x: "RLWNM [$]4, R[0-9]+, [$]28, [$]31,"
|
||||
b[7] = (b[7] >> 28) & 0xF
|
||||
// ppc64x: "RLWNM [$]11, R[0-9]+, [$]10, [$]15"
|
||||
c[0] = c[((v>>5)&0x3F)<<16]
|
||||
// ppc64x: "ANDCC [$]8064,"
|
||||
c[1] = c[((v>>7)&0x3F)<<7]
|
||||
}
|
||||
|
||||
func checkShiftMask(a uint32, b uint64, z []uint32, y []uint64) {
|
||||
_ = y[128]
|
||||
_ = z[128]
|
||||
// ppc64x: -"MOVBZ", -"SRW", "RLWNM"
|
||||
z[0] = uint32(uint8(a >> 5))
|
||||
// ppc64x: -"MOVBZ", -"SRW", "RLWNM"
|
||||
z[1] = uint32(uint8((a >> 4) & 0x7e))
|
||||
// ppc64x: "RLWNM [$]25, R[0-9]+, [$]27, [$]29, R[0-9]+"
|
||||
z[2] = uint32(uint8(a>>7)) & 0x1c
|
||||
// ppc64x: -"MOVWZ"
|
||||
y[0] = uint64((a >> 6) & 0x1c)
|
||||
// ppc64x: -"MOVWZ"
|
||||
y[1] = uint64(uint32(b)<<6) + 1
|
||||
// ppc64x: -"MOVHZ", -"MOVWZ"
|
||||
y[2] = uint64((uint16(a) >> 9) & 0x1F)
|
||||
// ppc64x: -"MOVHZ", -"MOVWZ", -"ANDCC"
|
||||
y[3] = uint64(((uint16(a) & 0xFF0) >> 9) & 0x1F)
|
||||
}
|
||||
|
||||
// 128 bit shifts
|
||||
|
||||
func check128bitShifts(x, y uint64, bits uint) (uint64, uint64) {
|
||||
s := bits & 63
|
||||
ŝ := (64 - bits) & 63
|
||||
// check that the shift operation has two commas (three operands)
|
||||
// amd64:"SHRQ.*,.*,"
|
||||
shr := x>>s | y<<ŝ
|
||||
// amd64:"SHLQ.*,.*,"
|
||||
shl := x<<s | y>>ŝ
|
||||
return shr, shl
|
||||
}
|
||||
|
||||
func checkShiftToMask(u []uint64, s []int64) {
|
||||
// amd64:-"SHR" -"SHL" "ANDQ"
|
||||
u[0] = u[0] >> 5 << 5
|
||||
// amd64:-"SAR" -"SHL" "ANDQ"
|
||||
s[0] = s[0] >> 5 << 5
|
||||
// amd64:-"SHR" -"SHL" "ANDQ"
|
||||
u[1] = u[1] << 5 >> 5
|
||||
}
|
||||
|
||||
//
|
||||
// Left shift with addition.
|
||||
//
|
||||
|
||||
func checkLeftShiftWithAddition(a int64, b int64) int64 {
|
||||
// riscv64/rva20u64: "SLLI" "ADD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "SH1ADD"
|
||||
a = a + b<<1
|
||||
// riscv64/rva20u64: "SLLI" "ADD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "SH2ADD"
|
||||
a = a + b<<2
|
||||
// riscv64/rva20u64: "SLLI" "ADD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "SH3ADD"
|
||||
a = a + b<<3
|
||||
return a
|
||||
}
|
||||
|
||||
//
|
||||
// Convert and shift.
|
||||
//
|
||||
|
||||
func rsh64Uto32U(v uint64) uint32 {
|
||||
x := uint32(v)
|
||||
// riscv64:"MOVWU"
|
||||
if x > 8 {
|
||||
// riscv64:"SRLIW" -"MOVWU" -"SLLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64Uto16U(v uint64) uint16 {
|
||||
x := uint16(v)
|
||||
// riscv64:"MOVHU"
|
||||
if x > 8 {
|
||||
// riscv64:"SLLI" "SRLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64Uto8U(v uint64) uint8 {
|
||||
x := uint8(v)
|
||||
// riscv64:"MOVBU"
|
||||
if x > 8 {
|
||||
// riscv64:"SLLI" "SRLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64to32(v int64) int32 {
|
||||
x := int32(v)
|
||||
// riscv64:"MOVW"
|
||||
if x > 8 {
|
||||
// riscv64:"SRLIW" -"MOVW" -"SLLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64to16(v int64) int16 {
|
||||
x := int16(v)
|
||||
// riscv64:"MOVH"
|
||||
if x > 8 {
|
||||
// riscv64:"SLLI" "SRLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64to8(v int64) int8 {
|
||||
x := int8(v)
|
||||
// riscv64:"MOVB"
|
||||
if x > 8 {
|
||||
// riscv64:"SLLI" "SRLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// We don't need to worry about shifting
|
||||
// more than the type size.
|
||||
// (There is still a negative shift test, but
|
||||
// no shift-too-big test.)
|
||||
func signedModShift(i int) int64 {
|
||||
// arm64:-"CMP" -"CSEL"
|
||||
return 1 << (i % 64)
|
||||
}
|
||||
17
test/codegen/shortcircuit.go
Normal file
17
test/codegen/shortcircuit.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2020 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
|
||||
|
||||
func efaceExtract(e interface{}) int {
|
||||
// This should be compiled with only
|
||||
// a single conditional jump.
|
||||
// amd64:-"JMP"
|
||||
if x, ok := e.(int); ok {
|
||||
return x
|
||||
}
|
||||
return 0
|
||||
}
|
||||
106
test/codegen/simd.go
Normal file
106
test/codegen/simd.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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.
|
||||
|
||||
// These tests check code generation of simd peephole optimizations.
|
||||
|
||||
//go:build goexperiment.simd && amd64
|
||||
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"math"
|
||||
"simd/archsimd"
|
||||
)
|
||||
|
||||
func vptest1() bool {
|
||||
v1 := archsimd.LoadUint64x2Slice([]uint64{0, 1})
|
||||
v2 := archsimd.LoadUint64x2Slice([]uint64{0, 0})
|
||||
// amd64:`VPTEST\s(.*)(.*)$`
|
||||
// amd64:`SETCS\s(.*)$`
|
||||
return v1.AndNot(v2).IsZero()
|
||||
}
|
||||
|
||||
func vptest2() bool {
|
||||
v1 := archsimd.LoadUint64x2Slice([]uint64{0, 1})
|
||||
v2 := archsimd.LoadUint64x2Slice([]uint64{0, 0})
|
||||
// amd64:`VPTEST\s(.*)(.*)$`
|
||||
// amd64:`SETEQ\s(.*)$`
|
||||
return v1.And(v2).IsZero()
|
||||
}
|
||||
|
||||
type Args2 struct {
|
||||
V0 archsimd.Uint8x32
|
||||
V1 archsimd.Uint8x32
|
||||
x string
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func simdStructNoSpill(a Args2) archsimd.Uint8x32 {
|
||||
// amd64:-`VMOVDQU\s.*$`
|
||||
return a.V0.Xor(a.V1)
|
||||
}
|
||||
|
||||
func simdStructWrapperNoSpill(a Args2) archsimd.Uint8x32 {
|
||||
// amd64:-`VMOVDQU\s.*$`
|
||||
a.x = "test"
|
||||
return simdStructNoSpill(a)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func simdArrayNoSpill(a [1]Args2) archsimd.Uint8x32 {
|
||||
// amd64:-`VMOVDQU\s.*$`
|
||||
return a[0].V0.Xor(a[0].V1)
|
||||
}
|
||||
|
||||
func simdArrayWrapperNoSpill(a [1]Args2) archsimd.Uint8x32 {
|
||||
// amd64:-`VMOVDQU\s.*$`
|
||||
a[0].x = "test"
|
||||
return simdArrayNoSpill(a)
|
||||
}
|
||||
|
||||
func simdFeatureGuardedMaskOpt() archsimd.Int16x16 {
|
||||
var x, y archsimd.Int16x16
|
||||
if archsimd.X86.AVX512() {
|
||||
mask := archsimd.Mask16x16FromBits(5)
|
||||
return x.Add(y).Masked(mask) // amd64:`VPADDW.Z\s.*$`
|
||||
}
|
||||
mask := archsimd.Mask16x16FromBits(5)
|
||||
return x.Add(y).Masked(mask) // amd64:`VPAND\s.*$`
|
||||
}
|
||||
|
||||
func simdMaskedMerge() archsimd.Int16x16 {
|
||||
var x, y archsimd.Int16x16
|
||||
if archsimd.X86.AVX512() {
|
||||
mask := archsimd.Mask16x16FromBits(5)
|
||||
return x.Add(y).Merge(x, mask) // amd64:-`VPBLENDVB\s.*$`
|
||||
}
|
||||
mask := archsimd.Mask16x16FromBits(5)
|
||||
return x.Add(y).Merge(x, mask) // amd64:`VPBLENDVB\s.*$`
|
||||
}
|
||||
|
||||
var nan = math.NaN()
|
||||
var floats64s = []float64{0, 1, 2, nan, 4, nan, 6, 7, 8, 9, 10, 11, nan, 13, 14, 15}
|
||||
var sinkInt64s = make([]int64, 100)
|
||||
|
||||
func simdIsNaN() {
|
||||
x := archsimd.LoadFloat64x4Slice(floats64s)
|
||||
y := archsimd.LoadFloat64x4Slice(floats64s[4:])
|
||||
a := x.IsNaN()
|
||||
b := y.IsNaN()
|
||||
// amd64:"VCMPPD [$]3," -"VPOR"
|
||||
c := a.Or(b)
|
||||
c.ToInt64x4().StoreSlice(sinkInt64s)
|
||||
}
|
||||
|
||||
func simdIsNaN512() {
|
||||
x := archsimd.LoadFloat64x8Slice(floats64s)
|
||||
y := archsimd.LoadFloat64x8Slice(floats64s[8:])
|
||||
a := x.IsNaN()
|
||||
b := y.IsNaN()
|
||||
// amd64:"VCMPPD [$]3," -"VPOR"
|
||||
c := a.Or(b)
|
||||
c.ToInt64x8().StoreSlice(sinkInt64s)
|
||||
}
|
||||
470
test/codegen/slices.go
Normal file
470
test/codegen/slices.go
Normal file
@@ -0,0 +1,470 @@
|
||||
// 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 "unsafe"
|
||||
|
||||
// This file contains code generation tests related to the handling of
|
||||
// slice types.
|
||||
|
||||
// ------------------ //
|
||||
// Clear //
|
||||
// ------------------ //
|
||||
|
||||
// Issue #5373 optimize memset idiom
|
||||
// Some of the clears get inlined, see #56997
|
||||
|
||||
func SliceClear(s []int) []int {
|
||||
// amd64:`.*memclrNoHeapPointers`
|
||||
// ppc64x:`.*memclrNoHeapPointers`
|
||||
for i := range s {
|
||||
s[i] = 0
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func SliceClearPointers(s []*int) []*int {
|
||||
// amd64:`.*memclrHasPointers`
|
||||
// ppc64x:`.*memclrHasPointers`
|
||||
for i := range s {
|
||||
s[i] = nil
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ------------------ //
|
||||
// Extension //
|
||||
// ------------------ //
|
||||
|
||||
// Issue #21266 - avoid makeslice in append(x, make([]T, y)...)
|
||||
|
||||
func SliceExtensionConst(s []int) []int {
|
||||
// amd64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:-`.*runtime\.panicmakeslicelen`
|
||||
// amd64:"MOVUPS X15"
|
||||
// loong64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
// ppc64x:-`.*runtime\.panicmakeslicelen`
|
||||
return append(s, make([]int, 1<<2)...)
|
||||
}
|
||||
|
||||
func SliceExtensionConstInt64(s []int) []int {
|
||||
// amd64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:-`.*runtime\.panicmakeslicelen`
|
||||
// amd64:"MOVUPS X15"
|
||||
// loong64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
// ppc64x:-`.*runtime\.panicmakeslicelen`
|
||||
return append(s, make([]int, int64(1<<2))...)
|
||||
}
|
||||
|
||||
func SliceExtensionConstUint64(s []int) []int {
|
||||
// amd64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:-`.*runtime\.panicmakeslicelen`
|
||||
// amd64:"MOVUPS X15"
|
||||
// loong64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
// ppc64x:-`.*runtime\.panicmakeslicelen`
|
||||
return append(s, make([]int, uint64(1<<2))...)
|
||||
}
|
||||
|
||||
func SliceExtensionConstUint(s []int) []int {
|
||||
// amd64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:-`.*runtime\.panicmakeslicelen`
|
||||
// amd64:"MOVUPS X15"
|
||||
// loong64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
// ppc64x:-`.*runtime\.panicmakeslicelen`
|
||||
return append(s, make([]int, uint(1<<2))...)
|
||||
}
|
||||
|
||||
// On ppc64x and loong64 continue to use memclrNoHeapPointers
|
||||
// for sizes >= 512.
|
||||
func SliceExtensionConst512(s []int) []int {
|
||||
// amd64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// loong64:`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:`.*runtime\.memclrNoHeapPointers`
|
||||
return append(s, make([]int, 1<<9)...)
|
||||
}
|
||||
|
||||
func SliceExtensionPointer(s []*int, l int) []*int {
|
||||
// amd64:`.*runtime\.memclrHasPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// ppc64x:`.*runtime\.memclrHasPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
return append(s, make([]*int, l)...)
|
||||
}
|
||||
|
||||
func SliceExtensionVar(s []byte, l int) []byte {
|
||||
// amd64:`.*runtime\.memclrNoHeapPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// ppc64x:`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
return append(s, make([]byte, l)...)
|
||||
}
|
||||
|
||||
func SliceExtensionVarInt64(s []byte, l int64) []byte {
|
||||
// amd64:`.*runtime\.memclrNoHeapPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:`.*runtime\.panicmakeslicelen`
|
||||
return append(s, make([]byte, l)...)
|
||||
}
|
||||
|
||||
func SliceExtensionVarUint64(s []byte, l uint64) []byte {
|
||||
// amd64:`.*runtime\.memclrNoHeapPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:`.*runtime\.panicmakeslicelen`
|
||||
return append(s, make([]byte, l)...)
|
||||
}
|
||||
|
||||
func SliceExtensionVarUint(s []byte, l uint) []byte {
|
||||
// amd64:`.*runtime\.memclrNoHeapPointers`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:`.*runtime\.panicmakeslicelen`
|
||||
return append(s, make([]byte, l)...)
|
||||
}
|
||||
|
||||
func SliceExtensionInt64(s []int, l64 int64) []int {
|
||||
// 386:`.*runtime\.makeslice`
|
||||
// 386:-`.*runtime\.memclr`
|
||||
return append(s, make([]int, l64)...)
|
||||
}
|
||||
|
||||
// ------------------ //
|
||||
// Make+Copy //
|
||||
// ------------------ //
|
||||
|
||||
// Issue #26252 - avoid memclr for make+copy
|
||||
|
||||
func SliceMakeCopyLen(s []int) []int {
|
||||
// amd64:`.*runtime\.mallocgc`
|
||||
// amd64:`.*runtime\.memmove`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// ppc64x:`.*runtime\.mallocgc`
|
||||
// ppc64x:`.*runtime\.memmove`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
a := make([]int, len(s))
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyLenPtr(s []*int) []*int {
|
||||
// amd64:`.*runtime\.makeslicecopy`
|
||||
// amd64:-`.*runtime\.makeslice\(`
|
||||
// amd64:-`.*runtime\.typedslicecopy
|
||||
// ppc64x:`.*runtime\.makeslicecopy`
|
||||
// ppc64x:-`.*runtime\.makeslice\(`
|
||||
// ppc64x:-`.*runtime\.typedslicecopy
|
||||
a := make([]*int, len(s))
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyConst(s []int) []int {
|
||||
// amd64:`.*runtime\.makeslicecopy`
|
||||
// amd64:-`.*runtime\.makeslice\(`
|
||||
// amd64:-`.*runtime\.memmove`
|
||||
a := make([]int, 4)
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyConstPtr(s []*int) []*int {
|
||||
// amd64:`.*runtime\.makeslicecopy`
|
||||
// amd64:-`.*runtime\.makeslice\(`
|
||||
// amd64:-`.*runtime\.typedslicecopy
|
||||
a := make([]*int, 4)
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptNoDeref(s []*int) []*int {
|
||||
a := new([]*int)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
*a = make([]*int, 4)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
copy(*a, s)
|
||||
return *a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptNoVar(s []*int) []*int {
|
||||
a := make([][]*int, 1)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
a[0] = make([]*int, 4)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
copy(a[0], s)
|
||||
return a[0]
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptBlank(s []*int) []*int {
|
||||
var a []*int
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
_ = make([]*int, 4)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptNoMake(s []*int) []*int {
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:-`.*runtime\.objectnew`
|
||||
a := *new([]*int)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptNoHeapAlloc(s []*int) int {
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
a := make([]*int, 4)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
copy(a, s)
|
||||
return cap(a)
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptNoCap(s []*int) []*int {
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
a := make([]*int, 0, 4)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptNoCopy(s []*int) []*int {
|
||||
copy := func(x, y []*int) {}
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
a := make([]*int, 4)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptWrongOrder(s []*int) []*int {
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
a := make([]*int, 4)
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
copy(s, a)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptWrongAssign(s []*int) []*int {
|
||||
var a []*int
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
s = make([]*int, 4)
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
copy(a, s)
|
||||
return s
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptCopyLength(s []*int) (int, []*int) {
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
a := make([]*int, 4)
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
n := copy(a, s)
|
||||
return n, a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptSelfCopy(s []*int) []*int {
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
a := make([]*int, 4)
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
copy(a, a)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptTargetReference(s []*int) []*int {
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
a := make([]*int, 4)
|
||||
// amd64:`.*runtime\.typedslicecopy`
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
copy(a, s[:len(a)])
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoOptCap(s []int) []int {
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.makeslice\(`
|
||||
a := make([]int, len(s), 9)
|
||||
// amd64:-`.*runtime\.makeslicecopy`
|
||||
// amd64:`.*runtime\.memmove`
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeCopyNoMemmoveDifferentLen(s []int) []int {
|
||||
// amd64:`.*runtime\.makeslicecopy`
|
||||
// amd64:-`.*runtime\.memmove`
|
||||
a := make([]int, len(s)-1)
|
||||
// amd64:-`.*runtime\.memmove`
|
||||
copy(a, s)
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceMakeEmptyPointerToZerobase() []int {
|
||||
// amd64:`LEAQ.+runtime\.zerobase`
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
return make([]int, 0)
|
||||
}
|
||||
|
||||
// ---------------------- //
|
||||
// Nil check of &s[0] //
|
||||
// ---------------------- //
|
||||
// See issue 30366
|
||||
func SliceNilCheck(s []int) {
|
||||
p := &s[0]
|
||||
// amd64:-`TESTB`
|
||||
_ = *p
|
||||
}
|
||||
|
||||
// ---------------------- //
|
||||
// Init slice literal //
|
||||
// ---------------------- //
|
||||
// See issue 21561
|
||||
func InitSmallSliceLiteral() []int {
|
||||
// amd64:`MOVQ [$]42`
|
||||
return []int{42}
|
||||
}
|
||||
|
||||
func InitNotSmallSliceLiteral() []int {
|
||||
// amd64:`LEAQ .*stmp_`
|
||||
return []int{
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------- //
|
||||
// Test PPC64 SUBFCconst folding rules //
|
||||
// triggered by slice operations. //
|
||||
// --------------------------------------- //
|
||||
|
||||
func SliceWithConstCompare(a []int, b int) []int {
|
||||
var c []int = []int{1, 2, 3, 4, 5}
|
||||
if b+len(a) < len(c) {
|
||||
// ppc64x:-"NEG"
|
||||
return c[b:]
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func SliceWithSubtractBound(a []int, b int) []int {
|
||||
// ppc64x:"SUBC" -"NEG"
|
||||
return a[(3 - b):]
|
||||
}
|
||||
|
||||
// --------------------------------------- //
|
||||
// ARM64 folding for slice masks //
|
||||
// --------------------------------------- //
|
||||
|
||||
func SliceAndIndex(a []int, b int) int {
|
||||
// arm64:"AND R[0-9]+->63" "ADD R[0-9]+<<3"
|
||||
return a[b:][b]
|
||||
}
|
||||
|
||||
// --------------------------------------- //
|
||||
// Code generation for unsafe.Slice //
|
||||
// --------------------------------------- //
|
||||
|
||||
func Slice1(p *byte, i int) []byte {
|
||||
// amd64:-"MULQ"
|
||||
return unsafe.Slice(p, i)
|
||||
}
|
||||
func Slice0(p *struct{}, i int) []struct{} {
|
||||
// amd64:-"MULQ"
|
||||
return unsafe.Slice(p, i)
|
||||
}
|
||||
|
||||
// --------------------------------------- //
|
||||
// Code generation for slice bounds //
|
||||
// checking comparison //
|
||||
// --------------------------------------- //
|
||||
|
||||
func SlicePut(a []byte, c uint8) []byte {
|
||||
// arm64:`CBZ R1`
|
||||
a[0] = c
|
||||
// arm64:`CMP \$1, R1`
|
||||
a = a[1:]
|
||||
a[0] = c
|
||||
// arm64:`CMP \$2, R1`
|
||||
a = a[1:]
|
||||
a[0] = c
|
||||
a = a[1:]
|
||||
return a
|
||||
}
|
||||
|
||||
func Issue61730() {
|
||||
var x int
|
||||
// amd64:-"MOVQ .*stmp_"
|
||||
_ = [...][]*int{
|
||||
{&x},
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
}
|
||||
}
|
||||
22
test/codegen/smallintiface.go
Normal file
22
test/codegen/smallintiface.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// asmcheck
|
||||
|
||||
package codegen
|
||||
|
||||
// Copyright 2020 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.
|
||||
|
||||
func booliface() interface{} {
|
||||
// amd64:`LEAQ runtime.staticuint64s\+8\(SB\)`
|
||||
return true
|
||||
}
|
||||
|
||||
func smallint8iface() interface{} {
|
||||
// amd64:`LEAQ runtime.staticuint64s\+2024\(SB\)`
|
||||
return int8(-3)
|
||||
}
|
||||
|
||||
func smalluint8iface() interface{} {
|
||||
// amd64:`LEAQ runtime.staticuint64s\+24\(SB\)`
|
||||
return uint8(3)
|
||||
}
|
||||
39
test/codegen/spectre.go
Normal file
39
test/codegen/spectre.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// asmcheck -gcflags=-spectre=index
|
||||
|
||||
//go:build amd64
|
||||
|
||||
// Copyright 2020 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
|
||||
|
||||
func IndexArray(x *[10]int, i int) int {
|
||||
// amd64:`CMOVQCC`
|
||||
return x[i]
|
||||
}
|
||||
|
||||
func IndexString(x string, i int) byte {
|
||||
// amd64:`CMOVQ(LS|CC)`
|
||||
return x[i]
|
||||
}
|
||||
|
||||
func IndexSlice(x []float64, i int) float64 {
|
||||
// amd64:`CMOVQ(LS|CC)`
|
||||
return x[i]
|
||||
}
|
||||
|
||||
func SliceArray(x *[10]int, i, j int) []int {
|
||||
// amd64:`CMOVQHI`
|
||||
return x[i:j]
|
||||
}
|
||||
|
||||
func SliceString(x string, i, j int) string {
|
||||
// amd64:`CMOVQHI`
|
||||
return x[i:j]
|
||||
}
|
||||
|
||||
func SliceSlice(x []float64, i, j int) []float64 {
|
||||
// amd64:`CMOVQHI`
|
||||
return x[i:j]
|
||||
}
|
||||
31
test/codegen/spills.go
Normal file
31
test/codegen/spills.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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
|
||||
|
||||
func i64(a, b int64) int64 { // arm64:`STP\s`,`LDP\s`
|
||||
g()
|
||||
return a + b
|
||||
}
|
||||
|
||||
func i32(a, b int32) int32 { // arm64:`STPW`,`LDPW`
|
||||
g()
|
||||
return a + b
|
||||
}
|
||||
|
||||
func f64(a, b float64) float64 { // arm64:`FSTPD`,`FLDPD`
|
||||
g()
|
||||
return a + b
|
||||
}
|
||||
|
||||
func f32(a, b float32) float32 { // arm64:`FSTPS`,`FLDPS`
|
||||
g()
|
||||
return a + b
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func g() {
|
||||
}
|
||||
176
test/codegen/stack.go
Normal file
176
test/codegen/stack.go
Normal file
@@ -0,0 +1,176 @@
|
||||
// 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 (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// This file contains code generation tests related to the use of the
|
||||
// stack.
|
||||
|
||||
// Check that stack stores are optimized away.
|
||||
|
||||
// 386:"TEXT .*, [$]0-"
|
||||
// amd64:"TEXT .*, [$]0-"
|
||||
// arm:"TEXT .*, [$]-4-"
|
||||
// arm64:"TEXT .*, [$]0-"
|
||||
// mips:"TEXT .*, [$]-4-"
|
||||
// ppc64x:"TEXT .*, [$]0-"
|
||||
// s390x:"TEXT .*, [$]0-"
|
||||
func StackStore() int {
|
||||
var x int
|
||||
return *(&x)
|
||||
}
|
||||
|
||||
type T struct {
|
||||
A, B, C, D int // keep exported fields
|
||||
x, y, z int // reset unexported fields
|
||||
}
|
||||
|
||||
// Check that large structs are cleared directly (issue #24416).
|
||||
|
||||
// 386:"TEXT .*, [$]0-"
|
||||
// amd64:"TEXT .*, [$]0-"
|
||||
// arm:"TEXT .*, [$]0-" (spills return address)
|
||||
// arm64:"TEXT .*, [$]0-"
|
||||
// mips:"TEXT .*, [$]-4-"
|
||||
// ppc64x:"TEXT .*, [$]0-"
|
||||
// s390x:"TEXT .*, [$]0-"
|
||||
func ZeroLargeStruct(x *T) {
|
||||
t := T{}
|
||||
*x = t
|
||||
}
|
||||
|
||||
// Check that structs are partially initialised directly (issue #24386).
|
||||
|
||||
// Notes:
|
||||
// - 386 fails due to spilling a register
|
||||
// amd64:"TEXT .*, [$]0-"
|
||||
// arm:"TEXT .*, [$]0-" (spills return address)
|
||||
// arm64:"TEXT .*, [$]0-"
|
||||
// ppc64x:"TEXT .*, [$]0-"
|
||||
// s390x:"TEXT .*, [$]0-"
|
||||
// Note: that 386 currently has to spill a register.
|
||||
func KeepWanted(t *T) {
|
||||
*t = T{A: t.A, B: t.B, C: t.C, D: t.D}
|
||||
}
|
||||
|
||||
// Check that small array operations avoid using the stack (issue #15925).
|
||||
|
||||
// Notes:
|
||||
// - 386 fails due to spilling a register
|
||||
// - arm & mips fail due to softfloat calls
|
||||
// amd64:"TEXT .*, [$]0-"
|
||||
// arm64:"TEXT .*, [$]0-"
|
||||
// ppc64x:"TEXT .*, [$]0-"
|
||||
// s390x:"TEXT .*, [$]0-"
|
||||
func ArrayAdd64(a, b [4]float64) [4]float64 {
|
||||
return [4]float64{a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]}
|
||||
}
|
||||
|
||||
// Check that small array initialization avoids using the stack.
|
||||
|
||||
// 386:"TEXT .*, [$]0-"
|
||||
// amd64:"TEXT .*, [$]0-"
|
||||
// arm:"TEXT .*, [$]0-" (spills return address)
|
||||
// arm64:"TEXT .*, [$]0-"
|
||||
// mips:"TEXT .*, [$]-4-"
|
||||
// ppc64x:"TEXT .*, [$]0-"
|
||||
// s390x:"TEXT .*, [$]0-"
|
||||
func ArrayInit(i, j int) [4]int {
|
||||
return [4]int{i, 0, j, 0}
|
||||
}
|
||||
|
||||
// Check that assembly output has matching offset and base register
|
||||
// (issue #21064).
|
||||
|
||||
func check_asmout(b [2]int) int {
|
||||
runtime.GC() // use some frame
|
||||
// amd64:`.*b\+24\(SP\)`
|
||||
// arm:`.*b\+4\(FP\)`
|
||||
return b[1]
|
||||
}
|
||||
|
||||
// Check that simple functions get promoted to nosplit, even when
|
||||
// they might panic in various ways. See issue 31219.
|
||||
// amd64:"TEXT .*NOSPLIT.*"
|
||||
func MightPanic(a []int, i, j, k, s int) {
|
||||
_ = a[i] // panicIndex
|
||||
_ = a[i:j] // panicSlice
|
||||
_ = a[i:j:k] // also panicSlice
|
||||
_ = i << s // panicShift
|
||||
_ = i / j // panicDivide
|
||||
}
|
||||
|
||||
// Put a defer in a loop, so second defer is not open-coded
|
||||
func Defer() {
|
||||
for i := 0; i < 2; i++ {
|
||||
defer func() {}()
|
||||
}
|
||||
// amd64:`CALL runtime\.deferprocStack`
|
||||
defer func() {}()
|
||||
}
|
||||
|
||||
// Check that stack slots are shared among values of the same
|
||||
// type, but not pointer-identical types. See issue 65783.
|
||||
|
||||
func spillSlotReuse() {
|
||||
// The return values of getp1 and getp2 need to be
|
||||
// spilled around the calls to nopInt. Make sure that
|
||||
// spill slot gets reused.
|
||||
|
||||
//arm64:`.*autotmp_2-8\(SP\)`
|
||||
getp1()[nopInt()] = 0
|
||||
//arm64:`.*autotmp_2-8\(SP\)`
|
||||
getp2()[nopInt()] = 0
|
||||
}
|
||||
|
||||
// Check that no stack frame space is needed for simple slice initialization with underlying structure.
|
||||
type mySlice struct {
|
||||
array unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
|
||||
// amd64:"TEXT .*, [$]0-"
|
||||
func sliceInit(base uintptr) []uintptr {
|
||||
const ptrSize = 8
|
||||
size := uintptr(4096)
|
||||
bitmapSize := size / ptrSize / 8
|
||||
elements := int(bitmapSize / ptrSize)
|
||||
var sl mySlice
|
||||
sl = mySlice{
|
||||
unsafe.Pointer(base + size - bitmapSize),
|
||||
elements,
|
||||
elements,
|
||||
}
|
||||
// amd64:-"POPQ" -"SP"
|
||||
return *(*[]uintptr)(unsafe.Pointer(&sl))
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func nopInt() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func getp1() *[4]int {
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func getp2() *[4]int {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Store to an argument without read can be removed.
|
||||
func storeArg(a [2]int) {
|
||||
// amd64:-`MOVQ \$123,.*\.a\+\d+\(SP\)`
|
||||
a[1] = 123
|
||||
}
|
||||
113
test/codegen/strings.go
Normal file
113
test/codegen/strings.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// 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 "strings"
|
||||
|
||||
// This file contains code generation tests related to the handling of
|
||||
// string types.
|
||||
|
||||
func CountRunes(s string) int { // Issue #24923
|
||||
// amd64:`.*countrunes`
|
||||
return len([]rune(s))
|
||||
}
|
||||
|
||||
func CountBytes(s []byte) int {
|
||||
// amd64:-`.*runtime.slicebytetostring`
|
||||
return len(string(s))
|
||||
}
|
||||
|
||||
func ToByteSlice() []byte { // Issue #24698
|
||||
// amd64:`LEAQ type:\[3\]uint8`
|
||||
// amd64:`CALL runtime\.(newobject|mallocgcTinySize3)`
|
||||
// amd64:-`.*runtime.stringtoslicebyte`
|
||||
return []byte("foo")
|
||||
}
|
||||
|
||||
func ConvertToByteSlice(a, b, c string) []byte {
|
||||
// amd64:`.*runtime.concatbyte3`
|
||||
return []byte(a + b + c)
|
||||
}
|
||||
|
||||
// Loading from read-only symbols should get transformed into constants.
|
||||
func ConstantLoad() {
|
||||
// 12592 = 0x3130
|
||||
// 50 = 0x32
|
||||
// amd64:`MOVW \$12592, \(`,`MOVB \$50, 2\(`
|
||||
// 386:`MOVW \$12592, \(`,`MOVB \$50, 2\(`
|
||||
// arm:`MOVW \$48`,`MOVW \$49`,`MOVW \$50`
|
||||
// arm64:`MOVD \$12592`,`MOVD \$50`
|
||||
// loong64:`MOVV \$12592`,`MOVV \$50`
|
||||
// wasm:`I64Const \$12592`,`I64Store16 \$0`,`I64Const \$50`,`I64Store8 \$2`
|
||||
// mips64:`MOVV \$48`,`MOVV \$49`,`MOVV \$50`
|
||||
bsink = []byte("012")
|
||||
|
||||
// 858927408 = 0x33323130
|
||||
// 13620 = 0x3534
|
||||
// amd64:`MOVL \$858927408`,`MOVW \$13620, 4\(`
|
||||
// 386:`MOVL \$858927408`,`MOVW \$13620, 4\(`
|
||||
// arm64:`MOVD \$858927408`,`MOVD \$13620`
|
||||
// loong64:`MOVV \$858927408`,`MOVV \$13620`
|
||||
// wasm:`I64Const \$858927408`,`I64Store32 \$0`,`I64Const \$13620`,`I64Store16 \$4`
|
||||
bsink = []byte("012345")
|
||||
|
||||
// 3978425819141910832 = 0x3736353433323130
|
||||
// 7306073769690871863 = 0x6564636261393837
|
||||
// amd64:`MOVQ \$3978425819141910832`,`MOVQ \$7306073769690871863`
|
||||
// 386:`MOVL \$858927408, \(`,`DUFFCOPY`
|
||||
// arm64:`MOVD \$3978425819141910832`,`MOVD \$7306073769690871863`,`MOVD \$15`
|
||||
// loong64:`MOVV \$3978425819141910832`,`MOVV \$7306073769690871863`,`MOVV \$15`
|
||||
// wasm:`I64Const \$3978425819141910832`,`I64Store \$0`,`I64Const \$7306073769690871863`,`I64Store \$7`
|
||||
bsink = []byte("0123456789abcde")
|
||||
|
||||
// 56 = 0x38
|
||||
// amd64:`MOVQ \$3978425819141910832`,`MOVB \$56`
|
||||
// loong64:`MOVV \$3978425819141910832`,`MOVV \$56`
|
||||
bsink = []byte("012345678")
|
||||
|
||||
// 14648 = 0x3938
|
||||
// amd64:`MOVQ \$3978425819141910832`,`MOVW \$14648`
|
||||
// loong64:`MOVV \$3978425819141910832`,`MOVV \$14648`
|
||||
bsink = []byte("0123456789")
|
||||
|
||||
// 1650538808 = 0x62613938
|
||||
// amd64:`MOVQ \$3978425819141910832`,`MOVL \$1650538808`
|
||||
// loong64:`MOVV \$3978425819141910832`,`MOVV \$1650538808`
|
||||
bsink = []byte("0123456789ab")
|
||||
}
|
||||
|
||||
// self-equality is always true. See issue 60777.
|
||||
func EqualSelf(s string) bool {
|
||||
// amd64:`MOVL \$1, AX`,-`.*memequal.*`
|
||||
return s == s
|
||||
}
|
||||
func NotEqualSelf(s string) bool {
|
||||
// amd64:`XORL AX, AX`,-`.*memequal.*`
|
||||
return s != s
|
||||
}
|
||||
|
||||
var bsink []byte
|
||||
|
||||
func HasPrefix3(s string) bool {
|
||||
// amd64:-`.*memequal.*`
|
||||
return strings.HasPrefix(s, "str")
|
||||
}
|
||||
|
||||
func HasPrefix5(s string) bool {
|
||||
// amd64:-`.*memequal.*`
|
||||
return strings.HasPrefix(s, "strin")
|
||||
}
|
||||
|
||||
func HasPrefix6(s string) bool {
|
||||
// amd64:-`.*memequal.*`
|
||||
return strings.HasPrefix(s, "string")
|
||||
}
|
||||
|
||||
func HasPrefix7(s string) bool {
|
||||
// amd64:-`.*memequal.*`
|
||||
return strings.HasPrefix(s, "strings")
|
||||
}
|
||||
48
test/codegen/structs.go
Normal file
48
test/codegen/structs.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// asmcheck
|
||||
|
||||
//go:build !goexperiment.cgocheck2
|
||||
|
||||
// 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
|
||||
|
||||
// This file contains code generation tests related to the handling of
|
||||
// struct types.
|
||||
|
||||
// ------------- //
|
||||
// Zeroing //
|
||||
// ------------- //
|
||||
|
||||
type Z1 struct {
|
||||
a, b, c int
|
||||
}
|
||||
|
||||
func Zero1(t *Z1) { // Issue #18370
|
||||
// amd64:`MOVUPS X[0-9]+, \(.*\)`,`MOVQ \$0, 16\(.*\)`
|
||||
*t = Z1{}
|
||||
}
|
||||
|
||||
type Z2 struct {
|
||||
a, b, c *int
|
||||
}
|
||||
|
||||
func Zero2(t *Z2) {
|
||||
// amd64:`MOVUPS X[0-9]+, \(.*\)`,`MOVQ \$0, 16\(.*\)`
|
||||
// amd64:`.*runtime[.]gcWriteBarrier.*\(SB\)`
|
||||
*t = Z2{}
|
||||
}
|
||||
|
||||
// ------------------ //
|
||||
// Initializing //
|
||||
// ------------------ //
|
||||
|
||||
type I1 struct {
|
||||
a, b, c, d int
|
||||
}
|
||||
|
||||
func Init1(p *I1) { // Issue #18872
|
||||
// amd64:`MOVQ [$]1`,`MOVQ [$]2`,`MOVQ [$]3`,`MOVQ [$]4`
|
||||
*p = I1{1, 2, 3, 4}
|
||||
}
|
||||
201
test/codegen/switch.go
Normal file
201
test/codegen/switch.go
Normal file
@@ -0,0 +1,201 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2019 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.
|
||||
|
||||
// These tests check code generation of switch statements.
|
||||
|
||||
package codegen
|
||||
|
||||
// see issue 33934
|
||||
func f(x string) int {
|
||||
// amd64:-`cmpstring`
|
||||
switch x {
|
||||
case "":
|
||||
return -1
|
||||
case "1", "2", "3":
|
||||
return -2
|
||||
default:
|
||||
return -3
|
||||
}
|
||||
}
|
||||
|
||||
// use jump tables for 8+ int cases
|
||||
func square(x int) int {
|
||||
// amd64:`JMP\s\(.*\)\(.*\)$`
|
||||
// arm64:`MOVD\s\(R.*\)\(R.*<<3\)`,`JMP\s\(R.*\)$`
|
||||
// loong64: `ALSLV`,`MOVV`,`JMP`
|
||||
switch x {
|
||||
case 1:
|
||||
return 1
|
||||
case 2:
|
||||
return 4
|
||||
case 3:
|
||||
return 9
|
||||
case 4:
|
||||
return 16
|
||||
case 5:
|
||||
return 25
|
||||
case 6:
|
||||
return 36
|
||||
case 7:
|
||||
return 49
|
||||
case 8:
|
||||
return 64
|
||||
default:
|
||||
return x * x
|
||||
}
|
||||
}
|
||||
|
||||
// use jump tables for 8+ string lengths
|
||||
func length(x string) int {
|
||||
// amd64:`JMP\s\(.*\)\(.*\)$`
|
||||
// arm64:`MOVD\s\(R.*\)\(R.*<<3\)`,`JMP\s\(R.*\)$`
|
||||
// loong64:`ALSLV`,`MOVV`,`JMP`
|
||||
switch x {
|
||||
case "a":
|
||||
return 1
|
||||
case "bb":
|
||||
return 2
|
||||
case "ccc":
|
||||
return 3
|
||||
case "dddd":
|
||||
return 4
|
||||
case "eeeee":
|
||||
return 5
|
||||
case "ffffff":
|
||||
return 6
|
||||
case "ggggggg":
|
||||
return 7
|
||||
case "hhhhhhhh":
|
||||
return 8
|
||||
default:
|
||||
return len(x)
|
||||
}
|
||||
}
|
||||
|
||||
// Use single-byte ordered comparisons for binary searching strings.
|
||||
// See issue 53333.
|
||||
func mimetype(ext string) string {
|
||||
// amd64: `CMPB\s1\(.*\), \$104$`,-`cmpstring`
|
||||
// arm64: `MOVB\s1\(R.*\), R.*$`, `CMPW\s\$104, R.*$`, -`cmpstring`
|
||||
switch ext {
|
||||
// amd64: `CMPL\s\(.*\), \$1836345390$`
|
||||
// arm64: `MOVD\s\$1836345390`, `CMPW\sR.*, R.*$`
|
||||
case ".htm":
|
||||
return "A"
|
||||
// amd64: `CMPL\s\(.*\), \$1953457454$`
|
||||
// arm64: `MOVD\s\$1953457454`, `CMPW\sR.*, R.*$`
|
||||
case ".eot":
|
||||
return "B"
|
||||
// amd64: `CMPL\s\(.*\), \$1735815982$`
|
||||
// arm64: `MOVD\s\$1735815982`, `CMPW\sR.*, R.*$`
|
||||
case ".svg":
|
||||
return "C"
|
||||
// amd64: `CMPL\s\(.*\), \$1718907950$`
|
||||
// arm64: `MOVD\s\$1718907950`, `CMPW\sR.*, R.*$`
|
||||
case ".ttf":
|
||||
return "D"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// use jump tables for type switches to concrete types.
|
||||
func typeSwitch(x any) int {
|
||||
// amd64:`JMP\s\(.*\)\(.*\)$`
|
||||
// arm64:`MOVD\s\(R.*\)\(R.*<<3\)`,`JMP\s\(R.*\)$`
|
||||
switch x.(type) {
|
||||
case int:
|
||||
return 0
|
||||
case int8:
|
||||
return 1
|
||||
case int16:
|
||||
return 2
|
||||
case int32:
|
||||
return 3
|
||||
case int64:
|
||||
return 4
|
||||
}
|
||||
return 7
|
||||
}
|
||||
|
||||
type I interface {
|
||||
foo()
|
||||
}
|
||||
type J interface {
|
||||
bar()
|
||||
}
|
||||
type IJ interface {
|
||||
I
|
||||
J
|
||||
}
|
||||
type K interface {
|
||||
baz()
|
||||
}
|
||||
|
||||
// use a runtime call for type switches to interface types.
|
||||
func interfaceSwitch(x any) int {
|
||||
// amd64:`CALL runtime.interfaceSwitch`,`MOVL 16\(AX\)`,`MOVQ 8\(.*\)(.*\*8)`
|
||||
// arm64:`CALL runtime.interfaceSwitch`,`LDAR`,`MOVWU 16\(R0\)`,`MOVD \(R.*\)\(R.*\)`
|
||||
switch x.(type) {
|
||||
case I:
|
||||
return 1
|
||||
case J:
|
||||
return 2
|
||||
default:
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
func interfaceSwitch2(x K) int {
|
||||
// amd64:`CALL runtime.interfaceSwitch`,`MOVL 16\(AX\)`,`MOVQ 8\(.*\)(.*\*8)`
|
||||
// arm64:`CALL runtime.interfaceSwitch`,`LDAR`,`MOVWU 16\(R0\)`,`MOVD \(R.*\)\(R.*\)`
|
||||
switch x.(type) {
|
||||
case I:
|
||||
return 1
|
||||
case J:
|
||||
return 2
|
||||
default:
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
func interfaceCast(x any) int {
|
||||
// amd64:`CALL runtime.typeAssert`,`MOVL 16\(AX\)`,`MOVQ 8\(.*\)(.*\*1)`
|
||||
// arm64:`CALL runtime.typeAssert`,`LDAR`,`MOVWU 16\(R0\)`,`MOVD \(R.*\)\(R.*\)`
|
||||
if _, ok := x.(I); ok {
|
||||
return 3
|
||||
}
|
||||
return 5
|
||||
}
|
||||
|
||||
func interfaceCast2(x K) int {
|
||||
// amd64:`CALL runtime.typeAssert`,`MOVL 16\(AX\)`,`MOVQ 8\(.*\)(.*\*1)`
|
||||
// arm64:`CALL runtime.typeAssert`,`LDAR`,`MOVWU 16\(R0\)`,`MOVD \(R.*\)\(R.*\)`
|
||||
if _, ok := x.(I); ok {
|
||||
return 3
|
||||
}
|
||||
return 5
|
||||
}
|
||||
|
||||
func interfaceConv(x IJ) I {
|
||||
// amd64:`CALL runtime.typeAssert`,`MOVL 16\(AX\)`,`MOVQ 8\(.*\)(.*\*1)`
|
||||
// arm64:`CALL runtime.typeAssert`,`LDAR`,`MOVWU 16\(R0\)`,`MOVD \(R.*\)\(R.*\)`
|
||||
return x
|
||||
}
|
||||
|
||||
// Make sure we can constant fold after inlining. See issue 71699.
|
||||
func stringSwitchInlineable(s string) {
|
||||
switch s {
|
||||
case "foo", "bar", "baz", "goo":
|
||||
default:
|
||||
println("no")
|
||||
}
|
||||
}
|
||||
func stringSwitch() {
|
||||
// amd64:-"CMP" -"CALL"
|
||||
// arm64:-"CMP" -"CALL"
|
||||
stringSwitchInlineable("foo")
|
||||
}
|
||||
67
test/codegen/typeswitch.go
Normal file
67
test/codegen/typeswitch.go
Normal file
@@ -0,0 +1,67 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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
|
||||
|
||||
type Ix interface {
|
||||
X()
|
||||
}
|
||||
|
||||
type Iy interface {
|
||||
Y()
|
||||
}
|
||||
|
||||
type Iz interface {
|
||||
Z()
|
||||
}
|
||||
|
||||
func swXYZ(a Ix) {
|
||||
switch t := a.(type) {
|
||||
case Iy: // amd64:-".*typeAssert"
|
||||
t.Y()
|
||||
case Iz: // amd64:-".*typeAssert"
|
||||
t.Z()
|
||||
}
|
||||
}
|
||||
|
||||
type Ig[T any] interface {
|
||||
G() T
|
||||
}
|
||||
|
||||
func swGYZ[T any](a Ig[T]) {
|
||||
switch t := a.(type) {
|
||||
case Iy: // amd64:-".*typeAssert"
|
||||
t.Y()
|
||||
case Iz: // amd64:-".*typeAssert"
|
||||
t.Z()
|
||||
case interface{ G() T }: // amd64:-".*typeAssert" -".*assertE2I\\(" ".*assertE2I2"
|
||||
t.G()
|
||||
}
|
||||
}
|
||||
|
||||
func swE2G[T any](a any) {
|
||||
switch t := a.(type) {
|
||||
case Iy:
|
||||
t.Y()
|
||||
case Ig[T]: // amd64:-".*assertE2I\\(" ".*assertE2I2"
|
||||
t.G()
|
||||
}
|
||||
}
|
||||
|
||||
func swI2G[T any](a Ix) {
|
||||
switch t := a.(type) {
|
||||
case Iy:
|
||||
t.Y()
|
||||
case Ig[T]: // amd64:-".*assertE2I\\(" ".*assertE2I2"
|
||||
t.G()
|
||||
}
|
||||
}
|
||||
|
||||
func swCaller() {
|
||||
swGYZ[int]((Ig[int])(nil))
|
||||
swE2G[int]((Ig[int])(nil))
|
||||
swI2G[int]((Ix)(nil))
|
||||
}
|
||||
24
test/codegen/unique.go
Normal file
24
test/codegen/unique.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2015 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 "unique"
|
||||
|
||||
func BytesToHandle(b []byte) unique.Handle[string] {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
return unique.Make(string(b))
|
||||
}
|
||||
|
||||
type Pair struct {
|
||||
S1 string
|
||||
S2 string
|
||||
}
|
||||
|
||||
func BytesPairToHandle(b1, b2 []byte) unique.Handle[Pair] {
|
||||
// TODO: should not copy b1 and b2.
|
||||
return unique.Make(Pair{string(b1), string(b2)})
|
||||
}
|
||||
16
test/codegen/unsafe.go
Normal file
16
test/codegen/unsafe.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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 "unsafe"
|
||||
|
||||
func f(p unsafe.Pointer, x, y uintptr) int64 {
|
||||
p = unsafe.Pointer(uintptr(p) + x + y)
|
||||
// amd64:`MOVQ\s\(.*\)\(.*\*1\), `
|
||||
// arm64:`MOVD\s\(R[0-9]+\)\(R[0-9]+\), `
|
||||
return *(*int64)(p)
|
||||
}
|
||||
103
test/codegen/writebarrier.go
Normal file
103
test/codegen/writebarrier.go
Normal file
@@ -0,0 +1,103 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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
|
||||
|
||||
func combine2string(p *[2]string, a, b string) {
|
||||
// amd64:`.*runtime[.]gcWriteBarrier4\(SB\)`
|
||||
// arm64:`.*runtime[.]gcWriteBarrier4\(SB\)`
|
||||
p[0] = a
|
||||
// amd64:-`.*runtime[.]gcWriteBarrier`
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[1] = b
|
||||
}
|
||||
|
||||
func combine4string(p *[4]string, a, b, c, d string) {
|
||||
// amd64:`.*runtime[.]gcWriteBarrier8\(SB\)`
|
||||
// arm64:`.*runtime[.]gcWriteBarrier8\(SB\)`
|
||||
p[0] = a
|
||||
// amd64:-`.*runtime[.]gcWriteBarrier`
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[1] = b
|
||||
// amd64:-`.*runtime[.]gcWriteBarrier`
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[2] = c
|
||||
// amd64:-`.*runtime[.]gcWriteBarrier`
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[3] = d
|
||||
}
|
||||
|
||||
func combine2slice(p *[2][]byte, a, b []byte) {
|
||||
// amd64:`.*runtime[.]gcWriteBarrier4\(SB\)`
|
||||
// arm64:`.*runtime[.]gcWriteBarrier4\(SB\)`
|
||||
p[0] = a
|
||||
// amd64:-`.*runtime[.]gcWriteBarrier`
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[1] = b
|
||||
}
|
||||
|
||||
func combine4slice(p *[4][]byte, a, b, c, d []byte) {
|
||||
// amd64:`.*runtime[.]gcWriteBarrier8\(SB\)`
|
||||
// arm64:`.*runtime[.]gcWriteBarrier8\(SB\)`
|
||||
p[0] = a
|
||||
// amd64:-`.*runtime[.]gcWriteBarrier`
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[1] = b
|
||||
// amd64:-`.*runtime[.]gcWriteBarrier`
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[2] = c
|
||||
// amd64:-`.*runtime[.]gcWriteBarrier`
|
||||
// arm64:-`.*runtime[.]gcWriteBarrier`
|
||||
p[3] = d
|
||||
}
|
||||
|
||||
func trickyWriteNil(p *int, q **int) {
|
||||
if p == nil {
|
||||
// We change "= p" to "= 0" in the prove pass, which
|
||||
// means we have one less pointer that needs to go
|
||||
// into the write barrier buffer.
|
||||
// amd64:`.*runtime[.]gcWriteBarrier1`
|
||||
*q = p
|
||||
}
|
||||
}
|
||||
|
||||
type S struct {
|
||||
a, b string
|
||||
c *int
|
||||
}
|
||||
|
||||
var g1, g2 *int
|
||||
|
||||
func issue71228(dst *S, ptr *int) {
|
||||
// Make sure that the non-write-barrier write.
|
||||
// "sp.c = ptr" happens before the large write
|
||||
// barrier "*dst = *sp". We approximate testing
|
||||
// that by ensuring that two global variable write
|
||||
// barriers aren't combined.
|
||||
_ = *dst
|
||||
var s S
|
||||
sp := &s
|
||||
//amd64:`.*runtime[.]gcWriteBarrier1`
|
||||
g1 = nil
|
||||
sp.c = ptr // outside of any write barrier
|
||||
//amd64:`.*runtime[.]gcWriteBarrier1`
|
||||
g2 = nil
|
||||
//amd64:`.*runtime[.]wbMove`
|
||||
*dst = *sp
|
||||
}
|
||||
|
||||
func writeDouble(p *[2]*int, x, y *int) {
|
||||
// arm64: `LDP\s`, `STP\s\(R[0-9]+, R[0-9]+\), \(`,
|
||||
p[0] = x
|
||||
// arm64: `STP\s\(R[0-9]+, R[0-9]+\), 16\(`,
|
||||
p[1] = y
|
||||
}
|
||||
|
||||
func writeDoubleNil(p *[2]*int) {
|
||||
// arm64: `LDP\s`, `STP\s\(R[0-9]+, R[0-9]+\),`, `STP\s\(ZR, ZR\),`
|
||||
p[0] = nil
|
||||
p[1] = nil
|
||||
}
|
||||
44
test/codegen/zerosize.go
Normal file
44
test/codegen/zerosize.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
|
||||
// Make sure a pointer variable and a zero-sized variable
|
||||
// aren't allocated to the same stack slot.
|
||||
// See issue 24993.
|
||||
|
||||
package codegen
|
||||
|
||||
func zeroSize() {
|
||||
c := make(chan struct{})
|
||||
// amd64:`MOVQ \$0, command-line-arguments\.s\+56\(SP\)`
|
||||
var s *int
|
||||
// force s to be a stack object, also use some (fixed) stack space
|
||||
g(&s, 1, 2, 3, 4, 5)
|
||||
|
||||
// amd64:`LEAQ command-line-arguments\..*\+55\(SP\)`
|
||||
c <- noliteral(struct{}{})
|
||||
}
|
||||
|
||||
// Like zeroSize, but without hiding the zero-sized struct.
|
||||
func zeroSize2() {
|
||||
c := make(chan struct{})
|
||||
// amd64:`MOVQ \$0, command-line-arguments\.s\+48\(SP\)`
|
||||
var s *int
|
||||
// force s to be a stack object, also use some (fixed) stack space
|
||||
g(&s, 1, 2, 3, 4, 5)
|
||||
|
||||
// amd64:`LEAQ command-line-arguments\..*stmp_\d+\(SB\)`
|
||||
c <- struct{}{}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func g(**int, int, int, int, int, int) {}
|
||||
|
||||
// noliteral prevents the compiler from recognizing a literal value.
|
||||
//
|
||||
//go:noinline
|
||||
func noliteral[T any](t T) T {
|
||||
return t
|
||||
}
|
||||
Reference in New Issue
Block a user