mirror of
https://github.com/golang/go
synced 2024-11-18 08:54:45 -07:00
cmd/compile: remove asmtest infrastructure
Not used anymore, all tests have been migrated to the top-level testsuite. Change-Id: I536e6c14f62153c01e4966ad41e1501b38494c7f Reviewed-on: https://go-review.googlesource.com/107336 Run-TryBot: Giovanni Bajo <rasky@develer.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
d0712096b3
commit
26085fcea3
@ -5,223 +5,15 @@
|
||||
package gc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// This file contains code generation tests.
|
||||
//
|
||||
// Each test is defined in a variable of type asmTest. Tests are
|
||||
// architecture-specific, and they are grouped in arrays of tests, one
|
||||
// for each architecture.
|
||||
//
|
||||
// Each asmTest consists of a function to compile, an array of
|
||||
// positive regexps that must match the generated assembly and
|
||||
// an array of negative regexps that must not match generated assembly.
|
||||
// For example, the following amd64 test
|
||||
//
|
||||
// {
|
||||
// fn: `
|
||||
// func f0(x int) int {
|
||||
// return x * 64
|
||||
// }
|
||||
// `,
|
||||
// pos: []string{"\tSHLQ\t[$]6,"},
|
||||
// neg: []string{"MULQ"}
|
||||
// }
|
||||
//
|
||||
// verifies that the code the compiler generates for a multiplication
|
||||
// by 64 contains a 'SHLQ' instruction and does not contain a MULQ.
|
||||
//
|
||||
// Since all the tests for a given architecture are dumped in the same
|
||||
// file, the function names must be unique. As a workaround for this
|
||||
// restriction, the test harness supports the use of a '$' placeholder
|
||||
// for function names. The func f0 above can be also written as
|
||||
//
|
||||
// {
|
||||
// fn: `
|
||||
// func $(x int) int {
|
||||
// return x * 64
|
||||
// }
|
||||
// `,
|
||||
// pos: []string{"\tSHLQ\t[$]6,"},
|
||||
// neg: []string{"MULQ"}
|
||||
// }
|
||||
//
|
||||
// Each '$'-function will be given a unique name of form f<N>_<arch>,
|
||||
// where <N> is the test index in the test array, and <arch> is the
|
||||
// test's architecture.
|
||||
//
|
||||
// It is allowed to mix named and unnamed functions in the same test
|
||||
// array; the named functions will retain their original names.
|
||||
|
||||
// TestAssembly checks to make sure the assembly generated for
|
||||
// functions contains certain expected instructions.
|
||||
func TestAssembly(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
if runtime.GOOS == "windows" {
|
||||
// TODO: remove if we can get "go tool compile -S" to work on windows.
|
||||
t.Skipf("skipping test: recursive windows compile not working")
|
||||
}
|
||||
dir, err := ioutil.TempDir("", "TestAssembly")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
nameRegexp := regexp.MustCompile("func \\w+")
|
||||
t.Run("platform", func(t *testing.T) {
|
||||
for _, ats := range allAsmTests {
|
||||
ats := ats
|
||||
t.Run(ats.os+"/"+ats.arch, func(tt *testing.T) {
|
||||
tt.Parallel()
|
||||
|
||||
asm := ats.compileToAsm(tt, dir)
|
||||
|
||||
for i, at := range ats.tests {
|
||||
var funcName string
|
||||
if strings.Contains(at.fn, "func $") {
|
||||
funcName = fmt.Sprintf("f%d_%s", i, ats.arch)
|
||||
} else {
|
||||
funcName = nameRegexp.FindString(at.fn)[len("func "):]
|
||||
}
|
||||
fa := funcAsm(tt, asm, funcName)
|
||||
if fa != "" {
|
||||
at.verifyAsm(tt, fa)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var nextTextRegexp = regexp.MustCompile(`\n\S`)
|
||||
|
||||
// funcAsm returns the assembly listing for the given function name.
|
||||
func funcAsm(t *testing.T, asm string, funcName string) string {
|
||||
if i := strings.Index(asm, fmt.Sprintf("TEXT\t\"\".%s(SB)", funcName)); i >= 0 {
|
||||
asm = asm[i:]
|
||||
} else {
|
||||
t.Errorf("could not find assembly for function %v", funcName)
|
||||
return ""
|
||||
}
|
||||
|
||||
// Find the next line that doesn't begin with whitespace.
|
||||
loc := nextTextRegexp.FindStringIndex(asm)
|
||||
if loc != nil {
|
||||
asm = asm[:loc[0]]
|
||||
}
|
||||
|
||||
return asm
|
||||
}
|
||||
|
||||
type asmTest struct {
|
||||
// function to compile
|
||||
fn string
|
||||
// regular expressions that must match the generated assembly
|
||||
pos []string
|
||||
// regular expressions that must not match the generated assembly
|
||||
neg []string
|
||||
}
|
||||
|
||||
func (at asmTest) verifyAsm(t *testing.T, fa string) {
|
||||
for _, r := range at.pos {
|
||||
if b, err := regexp.MatchString(r, fa); !b || err != nil {
|
||||
t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, at.fn, fa)
|
||||
}
|
||||
}
|
||||
for _, r := range at.neg {
|
||||
if b, err := regexp.MatchString(r, fa); b || err != nil {
|
||||
t.Errorf("not expected:%s\ngo:%s\nasm:%s\n", r, at.fn, fa)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type asmTests struct {
|
||||
arch string
|
||||
os string
|
||||
imports []string
|
||||
tests []*asmTest
|
||||
}
|
||||
|
||||
func (ats *asmTests) generateCode() []byte {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintln(&buf, "package main")
|
||||
for _, s := range ats.imports {
|
||||
fmt.Fprintf(&buf, "import %q\n", s)
|
||||
}
|
||||
|
||||
for i, t := range ats.tests {
|
||||
function := strings.Replace(t.fn, "func $", fmt.Sprintf("func f%d_%s", i, ats.arch), 1)
|
||||
fmt.Fprintln(&buf, function)
|
||||
}
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// compile compiles the package pkg for architecture arch and
|
||||
// returns the generated assembly. dir is a scratch directory.
|
||||
func (ats *asmTests) compileToAsm(t *testing.T, dir string) string {
|
||||
// create test directory
|
||||
testDir := filepath.Join(dir, fmt.Sprintf("%s_%s", ats.arch, ats.os))
|
||||
err := os.Mkdir(testDir, 0700)
|
||||
if err != nil {
|
||||
t.Fatalf("could not create directory: %v", err)
|
||||
}
|
||||
|
||||
// Create source.
|
||||
src := filepath.Join(testDir, "test.go")
|
||||
err = ioutil.WriteFile(src, ats.generateCode(), 0600)
|
||||
if err != nil {
|
||||
t.Fatalf("error writing code: %v", err)
|
||||
}
|
||||
|
||||
// First, install any dependencies we need. This builds the required export data
|
||||
// for any packages that are imported.
|
||||
for _, i := range ats.imports {
|
||||
out := filepath.Join(testDir, i+".a")
|
||||
|
||||
if s := ats.runGo(t, "build", "-o", out, "-gcflags=-dolinkobj=false", i); s != "" {
|
||||
t.Fatalf("Stdout = %s\nWant empty", s)
|
||||
}
|
||||
}
|
||||
|
||||
// Now, compile the individual file for which we want to see the generated assembly.
|
||||
asm := ats.runGo(t, "tool", "compile", "-I", testDir, "-S", "-o", filepath.Join(testDir, "out.o"), src)
|
||||
return asm
|
||||
}
|
||||
|
||||
// runGo runs go command with the given args and returns stdout string.
|
||||
// go is run with GOARCH and GOOS set as ats.arch and ats.os respectively
|
||||
func (ats *asmTests) runGo(t *testing.T, args ...string) string {
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := exec.Command(testenv.GoToolPath(t), args...)
|
||||
cmd.Env = append(os.Environ(), "GOARCH="+ats.arch, "GOOS="+ats.os)
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("error running cmd: %v\nstdout:\n%sstderr:\n%s\n", err, stdout.String(), stderr.String())
|
||||
}
|
||||
|
||||
if s := stderr.String(); s != "" {
|
||||
t.Fatalf("Stderr = %s\nWant empty", s)
|
||||
}
|
||||
|
||||
return stdout.String()
|
||||
}
|
||||
|
||||
var allAsmTests = []*asmTests{}
|
||||
|
||||
// TestLineNumber checks to make sure the generated assembly has line numbers
|
||||
// see issue #16214
|
||||
func TestLineNumber(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user