| | |
| | |
| | |
| |
|
| | 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 { |
| | |
| | |
| | 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: |
| |
|
| | |
| |
|
| | 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) |
| | } |
| |
|
| | It's possible to specify a comma-separated list of regexps to be |
| | matched. For example, the following test: |
| |
|
| | func TZ8(n uint8) int { |
| | |
| | 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: |
| |
|
| | |
| | |
| |
|
| | 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[:]) |
| | } |
| |
|
| | 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) { |
| | |
| | return a |
| | } |
| |
|
| | - Architecture specifiers |
| |
|
| | There are three different ways to specify on which architecture a test |
| | should be run: |
| |
|
| | |
| | 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). |
| | |
| | (eg: "arm/7"). This means that the check will be run only on that |
| | specific 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". |
| |
|