]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: testing harness for checking generated assembly
authorKeith Randall <khr@golang.org>
Tue, 24 May 2016 21:09:02 +0000 (14:09 -0700)
committerKeith Randall <khr@golang.org>
Thu, 26 May 2016 23:07:01 +0000 (23:07 +0000)
Add a test which compiles a function and checks the
generated assembly to make sure certain patterns are present.
This test allows us to do white box tests of the compiler
to make sure optimizations don't regress.

Added a few simple tests for now.  More to come.

Change-Id: I4ab5ce5d95b9e04e7d0d9328ffae47b8d1f95e74
Reviewed-on: https://go-review.googlesource.com/23403
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/asm_test.go [new file with mode: 0644]

diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go
new file mode 100644 (file)
index 0000000..469f086
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2016 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 gc
+
+import (
+       "bytes"
+       "fmt"
+       "internal/testenv"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "regexp"
+       "runtime"
+       "strings"
+       "testing"
+)
+
+// TestAssembly checks to make sure the assembly generated for
+// functions contains certain expected instructions.
+// Note: this test will fail if -ssa=0.
+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)
+
+       for _, test := range asmTests {
+               asm := compileToAsm(dir, test.arch, fmt.Sprintf(template, test.function))
+               // Get rid of code for "".init. Also gets rid of type algorithms & other junk.
+               if i := strings.Index(asm, "\n\"\".init "); i >= 0 {
+                       asm = asm[:i+1]
+               }
+               for _, r := range test.regexps {
+                       if b, err := regexp.MatchString(r, asm); !b || err != nil {
+                               t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, test.function, asm)
+                       }
+               }
+       }
+}
+
+// compile compiles the package pkg for architecture arch and
+// returns the generated assembly.  dir is a scratch directory.
+func compileToAsm(dir, arch, pkg string) string {
+       // Create source.
+       src := filepath.Join(dir, "test.go")
+       f, err := os.Create(src)
+       if err != nil {
+               panic(err)
+       }
+       f.Write([]byte(pkg))
+       f.Close()
+
+       var stdout, stderr bytes.Buffer
+       cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
+       cmd.Env = append(cmd.Env, "GOARCH="+arch)
+       cmd.Stdout = &stdout
+       cmd.Stderr = &stderr
+       if err := cmd.Run(); err != nil {
+               panic(err)
+       }
+       if s := stderr.String(); s != "" {
+               panic(fmt.Errorf("Stderr = %s\nWant empty", s))
+       }
+       return stdout.String()
+}
+
+// template to convert a function to a full file
+const template = `
+package main
+%s
+`
+
+type asmTest struct {
+       // architecture to compile to
+       arch string
+       // function to compile
+       function string
+       // regexps that must match the generated assembly
+       regexps []string
+}
+
+var asmTests = [...]asmTest{
+       {"amd64", `
+func f(x int) int {
+       return x * 64
+}
+`,
+               []string{"\tSHLQ\t\\$6,"},
+       },
+       {"amd64", `
+func f(x int) int {
+       return x * 96
+}`,
+               []string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"},
+       },
+}