]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/asm: add test for verification of instruction encodings
authorRuss Cox <rsc@golang.org>
Fri, 22 Jan 2016 01:48:21 +0000 (20:48 -0500)
committerRuss Cox <rsc@golang.org>
Sun, 24 Jan 2016 05:50:41 +0000 (05:50 +0000)
Not much testing yet, but the test now exists.

Another step toward #13822.

Change-Id: Idb2b06bf53a6113c83008150b4c0b631bb195279
Reviewed-on: https://go-review.googlesource.com/18844
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>

src/cmd/asm/internal/asm/endtoend_test.go
src/cmd/asm/internal/asm/testdata/amd64.s
src/cmd/asm/internal/asm/testdata/arm.s
src/cmd/internal/obj/arm/asm5.go

index bba82b5fca0a451bdafd84f171133537b8022324..620bb9741752b92aeb77b10815a40da4e646a03d 100644 (file)
@@ -10,6 +10,7 @@ import (
        "io/ioutil"
        "os"
        "path/filepath"
+       "sort"
        "strconv"
        "strings"
        "testing"
@@ -22,9 +23,9 @@ import (
 // Output is generated by, in effect, turning on -S and comparing the
 // result against a golden file.
 
-func testEndToEnd(t *testing.T, goarch string) {
+func testEndToEnd(t *testing.T, goarch, file string) {
        lex.InitHist()
-       input := filepath.Join("testdata", goarch+".s")
+       input := filepath.Join("testdata", file+".s")
        architecture, ctxt := setArch(goarch)
        lexer := lex.NewLexer(input, ctxt)
        parser := NewParser(ctxt, architecture, lexer)
@@ -33,23 +34,31 @@ func testEndToEnd(t *testing.T, goarch string) {
        testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
        ctxt.Bso = obj.Binitw(os.Stdout)
        defer ctxt.Bso.Flush()
-       ctxt.Diag = t.Errorf
+       failed := false
+       ctxt.Diag = func(format string, args ...interface{}) {
+               failed = true
+               t.Errorf(format, args...)
+       }
        obj.Binitw(ioutil.Discard)
        pList.Firstpc, ok = parser.Parse()
-       if !ok || t.Failed() {
-               t.Fatalf("asm: %s assembly failed", goarch)
+       if !ok || failed {
+               t.Errorf("asm: %s assembly failed", goarch)
+               return
        }
        output := strings.Split(testOut.String(), "\n")
 
        // Reconstruct expected output by independently "parsing" the input.
        data, err := ioutil.ReadFile(input)
        if err != nil {
-               t.Fatal(err)
+               t.Error(err)
+               return
        }
        lineno := 0
        seq := 0
+       hexByLine := map[string]string{}
+       lines := strings.SplitAfter(string(data), "\n")
 Diff:
-       for _, line := range strings.SplitAfter(string(data), "\n") {
+       for _, line := range lines {
                lineno++
 
                // The general form of a test input line is:
@@ -62,14 +71,31 @@ Diff:
                }
                seq++
 
+               var hexes string
                switch len(parts) {
                default:
                        t.Errorf("%s:%d: unable to understand comments: %s", input, lineno, line)
                case 1:
                        // no comment
                case 2:
-                       // one comment, printed form
+                       // might be printed form or hex
+                       note := strings.TrimSpace(parts[1])
+                       if isHexes(note) {
+                               hexes = note
+                       } else {
+                               printed = note
+                       }
+               case 3:
+                       // printed form, then hex
                        printed = strings.TrimSpace(parts[1])
+                       hexes = strings.TrimSpace(parts[2])
+                       if !isHexes(hexes) {
+                               t.Errorf("%s:%d: malformed hex instruction encoding: %s", input, lineno, line)
+                       }
+               }
+
+               if hexes != "" {
+                       hexByLine[fmt.Sprintf("%s:%d", input, lineno)] = hexes
                }
 
                // Canonicalize spacing in printed form.
@@ -142,28 +168,114 @@ Diff:
                t.Errorf("unexpected output: %q", output[0])
                output = output[1:]
        }
+
+       // Checked printing.
+       // Now check machine code layout.
+
+       top := pList.Firstpc
+       var text *obj.LSym
+       ok = true
+       ctxt.Diag = func(format string, args ...interface{}) {
+               t.Errorf(format, args...)
+               ok = false
+       }
+       obj.Flushplist(ctxt)
+
+       for p := top; p != nil; p = p.Link {
+               if p.As == obj.ATEXT {
+                       text = p.From.Sym
+               }
+               hexes := hexByLine[p.Line()]
+               if hexes == "" {
+                       continue
+               }
+               delete(hexByLine, p.Line())
+               if text == nil {
+                       t.Errorf("%s: instruction outside TEXT", p)
+               }
+               size := int64(len(text.P)) - p.Pc
+               if p.Link != nil {
+                       size = p.Link.Pc - p.Pc
+               } else if p.Isize != 0 {
+                       size = int64(p.Isize)
+               }
+               var code []byte
+               if p.Pc < int64(len(text.P)) {
+                       code = text.P[p.Pc:]
+                       if size < int64(len(code)) {
+                               code = code[:size]
+                       }
+               }
+               codeHex := fmt.Sprintf("%x", code)
+               if codeHex == "" {
+                       codeHex = "empty"
+               }
+               ok := false
+               for _, hex := range strings.Split(hexes, " or ") {
+                       if codeHex == hex {
+                               ok = true
+                               break
+                       }
+               }
+               if !ok {
+                       t.Errorf("%s: have encoding %s, want %s", p, codeHex, hexes)
+               }
+       }
+
+       if len(hexByLine) > 0 {
+               var missing []string
+               for key := range hexByLine {
+                       missing = append(missing, key)
+               }
+               sort.Strings(missing)
+               for _, line := range missing {
+                       t.Errorf("%s: did not find instruction encoding", line)
+               }
+       }
+
 }
 
-func TestPPC64EndToEnd(t *testing.T) {
-       testEndToEnd(t, "ppc64")
+func isHexes(s string) bool {
+       if s == "" {
+               return false
+       }
+       if s == "empty" {
+               return true
+       }
+       for _, f := range strings.Split(s, " or ") {
+               if f == "" || len(f)%2 != 0 || strings.TrimLeft(f, "0123456789abcdef") != "" {
+                       return false
+               }
+       }
+       return true
+}
+
+func Test386EndToEnd(t *testing.T) {
+       testEndToEnd(t, "386", "386")
 }
 
 func TestARMEndToEnd(t *testing.T) {
-       testEndToEnd(t, "arm")
+       defer os.Setenv("GOARM", os.Getenv("GOARM"))
+
+       for _, goarm := range []string{"5", "6", "7"} {
+               os.Setenv("GOARM", goarm)
+               t.Logf("GOARM=%v", os.Getenv("GOARM"))
+               testEndToEnd(t, "arm", "arm")
+       }
 }
 
 func TestARM64EndToEnd(t *testing.T) {
-       testEndToEnd(t, "arm64")
+       testEndToEnd(t, "arm64", "arm64")
 }
 
 func TestAMD64EndToEnd(t *testing.T) {
-       testEndToEnd(t, "amd64")
+       testEndToEnd(t, "amd64", "amd64")
 }
 
-func Test386EndToEnd(t *testing.T) {
-       testEndToEnd(t, "386")
+func TestMIPS64EndToEnd(t *testing.T) {
+       testEndToEnd(t, "mips64", "mips64")
 }
 
-func TestMIPS64EndToEnd(t *testing.T) {
-       testEndToEnd(t, "mips64")
+func TestPPC64EndToEnd(t *testing.T) {
+       testEndToEnd(t, "ppc64", "ppc64")
 }
index 35af32a5cd49534e400027439743a044fb65e4a4..5512df00348583671cc455df58c38911486abe74 100644 (file)
@@ -122,4 +122,4 @@ loop:
        LOOP    loop // LOOP
 
 // LTYPE0 nonnon       { outcode($1, &$2); }
-       RET
+       RET // c3
index 0102cd84146349e34502be4483877d83e340f28f..8062750250386df4cf21388a1e71ec24a5439bb8 100644 (file)
@@ -189,7 +189,7 @@ TEXT        foo(SB), 7, $0
 //             outcode($1, $2, &$3, 0, &$5);
 //     }
        ADDD.S  F1, F2
-       MOVF.S  $0.5, F2 // MOVF.S $(0.5), F2
+       MOVF    $0.5, F2 // MOVF $(0.5), F2
 
 //     LTYPEK cond frcon ',' LFREG ',' freg
 //     {
index f78b08445ffd6c06c9cc1ab8e40d4be17d5bbd0a..d75a16354cba9ac66913bbbd2f8544ff25050d50 100644 (file)
@@ -2737,7 +2737,7 @@ func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
 
 func ofsr(ctxt *obj.Link, a int, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
        if sc&C_SBIT != 0 {
-               ctxt.Diag(".nil on FLDR/FSTR instruction")
+               ctxt.Diag(".nil on FLDR/FSTR instruction: %v", p)
        }
        o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
        if sc&C_PBIT == 0 {