2018-03-07 04:54:28 -07:00
|
|
|
// 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
|
2019-09-01 09:30:56 -06:00
|
|
|
matches the generated assembly (the output of `go tool compile -S`)
|
|
|
|
against a set of regexps to be specified in comments that follow a
|
2023-02-08 09:40:06 -07:00
|
|
|
special syntax (described below). The test driver is implemented as
|
|
|
|
an action within the GOROOT/test test suite, called "asmcheck".
|
2018-03-07 04:54:28 -07:00
|
|
|
|
2019-09-01 09:30:56 -06:00
|
|
|
The codegen harness is part of the all.bash test suite, but for
|
|
|
|
performance reasons only the codegen tests for the host machine's
|
test/codegen: mention in README that tests only run on Linux without -all_codegen
This took me a while to figure out. The relevant code is in
test/run.go (note the "linux" hard-coded strings):
var arch, subarch, os string
switch {
case archspec[2] != "": // 3 components: "linux/386/sse2"
os, arch, subarch = archspec[0], archspec[1][1:], archspec[2][1:]
case archspec[1] != "": // 2 components: "386/sse2"
os, arch, subarch = "linux", archspec[0], archspec[1][1:]
default: // 1 component: "386"
os, arch, subarch = "linux", archspec[0], ""
if arch == "wasm" {
os = "js"
}
}
Change-Id: I92ba280025d2072e17532a5e43cf1d676789c167
Reviewed-on: https://go-review.googlesource.com/c/go/+/222819
Reviewed-by: Keith Randall <khr@golang.org>
2020-03-10 11:31:15 -06:00
|
|
|
GOARCH are enabled by default, and only on GOOS=linux.
|
|
|
|
|
|
|
|
To perform comprehensive tests for all the supported architectures
|
2023-02-08 09:40:06 -07:00
|
|
|
(even on a non-Linux system), one can run the following command:
|
2018-03-07 04:54:28 -07:00
|
|
|
|
2023-05-09 07:50:19 -06:00
|
|
|
$ ../../bin/go test cmd/internal/testdir -run='Test/codegen' -all_codegen -v
|
2018-03-07 04:54:28 -07:00
|
|
|
|
2023-02-08 09:40:06 -07:00
|
|
|
This is recommended after any change that affect the compiler's code.
|
2018-03-07 04:54:28 -07:00
|
|
|
|
|
|
|
The test harness compiles the tests with the same go toolchain that is
|
2023-02-08 09:40:06 -07:00
|
|
|
used to run the test. After writing tests for a newly added codegen
|
2018-03-07 04:54:28 -07:00
|
|
|
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-runnig 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.
|
|
|
|
|
2019-09-01 09:30:56 -06:00
|
|
|
|
2018-04-15 11:00:27 -06:00
|
|
|
- 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.
|
|
|
|
|
2018-03-07 04:54:28 -07:00
|
|
|
|
|
|
|
- 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.
|
|
|
|
|
2017-05-09 13:48:23 -06:00
|
|
|
Any given line of Go code could get assigned more instructions than it
|
2018-03-07 04:54:28 -07:00
|
|
|
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".
|