Skip to content

Commit a5ba581

Browse files
committed
cmd/asm: simplify golden test maintenance
Instead of two parallel files that look almost identical, mark the expected differences in the original file. The annotations being added here keep the tests passing, but they also make clear a number of printing or parsing errors that were not as easily seen when the data was split across two files. Fix a few diagnostic problems in cmd/internal/obj as well. A step toward #13822. Change-Id: I997172681ea6fa7da915ff0f0ab93d2b76f8dce2 Reviewed-on: https://go-review.googlesource.com/18823 Run-TryBot: Russ Cox <[email protected]> Reviewed-by: Rob Pike <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent e8b53c9 commit a5ba581

File tree

19 files changed

+286
-602
lines changed

19 files changed

+286
-602
lines changed

src/cmd/asm/internal/arch/arm.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ var armSCOND = map[string]uint8{
6262
var armJump = map[string]bool{
6363
"B": true,
6464
"BL": true,
65+
"BX": true,
6566
"BEQ": true,
6667
"BNE": true,
6768
"BCS": true,

src/cmd/asm/internal/asm/asm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
6363
fmt.Println(p.histLineNum, prog)
6464
}
6565
if testOut != nil {
66-
fmt.Fprintln(testOut, p.histLineNum, prog)
66+
fmt.Fprintln(testOut, prog)
6767
}
6868
}
6969

src/cmd/asm/internal/asm/endtoend_test.go

Lines changed: 98 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88
"bytes"
99
"fmt"
1010
"io/ioutil"
11-
"log"
1211
"os"
1312
"path/filepath"
13+
"strconv"
1414
"strings"
1515
"testing"
1616

@@ -25,48 +25,122 @@ import (
2525
func testEndToEnd(t *testing.T, goarch string) {
2626
lex.InitHist()
2727
input := filepath.Join("testdata", goarch+".s")
28-
output := filepath.Join("testdata", goarch+".out")
2928
architecture, ctxt := setArch(goarch)
3029
lexer := lex.NewLexer(input, ctxt)
3130
parser := NewParser(ctxt, architecture, lexer)
3231
pList := obj.Linknewplist(ctxt)
3332
var ok bool
34-
testOut = new(bytes.Buffer) // The assembler writes -S output to this buffer.
33+
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
3534
ctxt.Bso = obj.Binitw(os.Stdout)
3635
defer ctxt.Bso.Flush()
37-
ctxt.Diag = log.Fatalf
36+
ctxt.Diag = t.Errorf
3837
obj.Binitw(ioutil.Discard)
3938
pList.Firstpc, ok = parser.Parse()
40-
if !ok {
39+
if !ok || t.Failed() {
4140
t.Fatalf("asm: %s assembly failed", goarch)
4241
}
43-
result := string(testOut.Bytes())
44-
expect, err := ioutil.ReadFile(output)
45-
// For Windows.
46-
result = strings.Replace(result, `testdata\`, `testdata/`, -1)
42+
output := strings.Split(testOut.String(), "\n")
43+
44+
// Reconstruct expected output by independently "parsing" the input.
45+
data, err := ioutil.ReadFile(input)
4746
if err != nil {
4847
t.Fatal(err)
4948
}
50-
if result != string(expect) {
51-
if false { // Enable to capture output.
52-
fmt.Printf("%s", result)
53-
os.Exit(1)
49+
lineno := 0
50+
seq := 0
51+
Diff:
52+
for _, line := range strings.SplitAfter(string(data), "\n") {
53+
lineno++
54+
55+
// The general form of a test input line is:
56+
// // comment
57+
// INST args [// printed form] [// hex encoding]
58+
parts := strings.Split(line, "//")
59+
printed := strings.TrimSpace(parts[0])
60+
if printed == "" || strings.HasSuffix(printed, ":") { // empty or label
61+
continue
5462
}
55-
t.Errorf("%s failed: output differs", goarch)
56-
r := strings.Split(result, "\n")
57-
e := strings.Split(string(expect), "\n")
58-
if len(r) != len(e) {
59-
t.Errorf("%s: expected %d lines, got %d", goarch, len(e), len(r))
63+
seq++
64+
65+
switch len(parts) {
66+
default:
67+
t.Errorf("%s:%d: unable to understand comments: %s", input, lineno, line)
68+
case 1:
69+
// no comment
70+
case 2:
71+
// one comment, printed form
72+
printed = strings.TrimSpace(parts[1])
6073
}
61-
n := len(e)
62-
if n > len(r) {
63-
n = len(r)
74+
75+
// Canonicalize spacing in printed form.
76+
// First field is opcode, then tab, then arguments separated by spaces.
77+
// Canonicalize spaces after commas first.
78+
// Comma to separate argument gets a space; comma within does not.
79+
var buf []byte
80+
nest := 0
81+
for i := 0; i < len(printed); i++ {
82+
c := printed[i]
83+
switch c {
84+
case '{', '[':
85+
nest++
86+
case '}', ']':
87+
nest--
88+
case ',':
89+
buf = append(buf, ',')
90+
if nest == 0 {
91+
buf = append(buf, ' ')
92+
}
93+
for i+1 < len(printed) && (printed[i+1] == ' ' || printed[i+1] == '\t') {
94+
i++
95+
}
96+
continue
97+
}
98+
buf = append(buf, c)
6499
}
65-
for i := 0; i < n; i++ {
66-
if r[i] != e[i] {
67-
t.Errorf("%s:%d:\nexpected\n\t%s\ngot\n\t%s", output, i, e[i], r[i])
100+
101+
f := strings.Fields(string(buf))
102+
103+
// Turn relative (PC) into absolute (PC) automatically,
104+
// so that most branch instructions don't need comments
105+
// giving the absolute form.
106+
if len(f) > 0 && strings.HasSuffix(printed, "(PC)") {
107+
last := f[len(f)-1]
108+
n, err := strconv.Atoi(last[:len(last)-len("(PC)")])
109+
if err == nil {
110+
f[len(f)-1] = fmt.Sprintf("%d(PC)", seq+n)
68111
}
69112
}
113+
114+
if len(f) == 1 {
115+
printed = f[0]
116+
} else {
117+
printed = f[0] + "\t" + strings.Join(f[1:], " ")
118+
}
119+
120+
want := fmt.Sprintf("%05d (%s:%d)\t%s", seq, input, lineno, printed)
121+
for len(output) > 0 && (output[0] < want || output[0] != want && len(output[0]) >= 5 && output[0][:5] == want[:5]) {
122+
if len(output[0]) >= 5 && output[0][:5] == want[:5] {
123+
t.Errorf("mismatched output:\nhave %s\nwant %s", output[0], want)
124+
output = output[1:]
125+
continue Diff
126+
}
127+
t.Errorf("unexpected output: %q", output[0])
128+
output = output[1:]
129+
}
130+
if len(output) > 0 && output[0] == want {
131+
output = output[1:]
132+
} else {
133+
t.Errorf("missing output: %q", want)
134+
}
135+
}
136+
for len(output) > 0 {
137+
if output[0] == "" {
138+
// spurious blank caused by Split on "\n"
139+
output = output[1:]
140+
continue
141+
}
142+
t.Errorf("unexpected output: %q", output[0])
143+
output = output[1:]
70144
}
71145
}
72146

src/cmd/asm/internal/asm/testdata/386.out

Lines changed: 0 additions & 49 deletions
This file was deleted.

src/cmd/asm/internal/asm/testdata/386.s

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// the old assembler's (8a's) grammar and hand-writing complete
33
// instructions for each rule, to guarantee we cover the same space.
44

5-
TEXT foo(SB), 0, $0
5+
TEXT foo(SB), 7, $0
66

77
// LTYPE1 nonrem { outcode(int($1), &$2); }
88
SETCC AX
@@ -12,7 +12,7 @@ TEXT foo(SB), 0, $0
1212
DIVB AX
1313
DIVB foo+4(SB)
1414
PUSHL $foo+4(SB)
15-
POPL AX // balance PUSHL
15+
POPL AX
1616

1717
// LTYPE3 rimrem { outcode(int($1), &$2); }
1818
SUBB $1, AX
@@ -28,27 +28,31 @@ TEXT foo(SB), 0, $0
2828

2929
// LTYPER nonrel { outcode(int($1), &$2); }
3030
label:
31-
JC label
32-
JC -1(PC)
31+
JC label // JCS
32+
JC -1(PC) // JCS -1(PC)
3333

3434
// LTYPEC spec3 { outcode(int($1), &$2); }
3535
CALL AX
36-
JMP *AX
36+
JCS 2(PC)
37+
JMP *AX // JMP AX
3738
CALL *foo(SB)
39+
JCS 2(PC)
3840
JMP $4
39-
JMP label
41+
JCS 2(PC)
42+
JMP label // JMP 16
4043
CALL foo(SB)
41-
CALL (AX*4)
44+
// CALL (AX*4) // TODO: This line is silently dropped on the floor!
4245
CALL foo+4(SB)(AX*4)
43-
CALL *4(SP)
44-
CALL *(AX)
45-
CALL *(SP)
46-
CALL *(AX*4)
47-
CALL *(AX)(AX*4)
46+
CALL *4(SP) // CALL 4(SP)
47+
CALL *(AX) // CALL (AX)
48+
CALL *(SP) // CALL (SP)
49+
// CALL *(AX*4) // TODO: This line is silently dropped on the floor!
50+
CALL *(AX)(AX*4) // CALL (AX)(AX*4)
4851
CALL 4(SP)
4952
CALL (AX)
5053
CALL (SP)
51-
CALL (AX*4)
54+
// CALL (AX*4) // TODO: This line is silently dropped on the floor!
55+
JCS 2(PC)
5256
JMP (AX)(AX*4)
5357

5458
// LTYPEN spec4 { outcode(int($1), &$2); }
@@ -59,7 +63,7 @@ label:
5963
// LTYPES spec5 { outcode(int($1), &$2); }
6064
SHLL $4, BX
6165
SHLL $4, foo+4(SB)
62-
SHLL $4, foo+4(SB):AX
66+
SHLL $4, foo+4(SB):AX // SHLL $4, AX, foo+4(SB)
6367

6468
// LTYPEM spec6 { outcode(int($1), &$2); }
6569
MOVL AX, BX
@@ -72,15 +76,16 @@ label:
7276

7377
// LTYPEXC spec9 { outcode(int($1), &$2); }
7478
CMPPD X0, X1, 4
75-
CMPPD X0, foo+4(SB), 4
79+
CMPPD foo+4(SB), X1, 4
7680

7781
// LTYPEX spec10 { outcode(int($1), &$2); }
7882
PINSRD $1, (AX), X0
7983
PINSRD $2, foo+4(FP), X0
8084

8185
// Was bug: LOOP is a branch instruction.
86+
JCS 2(PC)
8287
loop:
83-
LOOP loop
88+
LOOP loop // LOOP
8489

8590
// LTYPE0 nonnon { outcode(int($1), &$2); }
8691
RET

src/cmd/asm/internal/asm/testdata/amd64.out

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)