aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2015-02-20 10:06:44 -0800
committerRob Pike <r@golang.org>2015-02-21 02:02:23 +0000
commit634049dbe64e39ffe7becfaf9629e409ce62b2dc (patch)
treedd92ab45ece44b51a76e9a173ba68733aa508a9f
parent5d111b898ad83fc09470f1a98f481f4e9f5a4cdf (diff)
downloadgo-634049dbe64e39ffe7becfaf9629e409ce62b2dc.tar.gz
go-634049dbe64e39ffe7becfaf9629e409ce62b2dc.zip
[dev.cc] cmd/asm: add end-to-end test
Add trivial golden test that verifies output matches expectation. The input is based on the old grammar and is intended to cover the space of the input language. PPC64 and ARM only for now; others to follow. Change-Id: Ib5957822bcafd5b9d4c1dea1c03cc6ee1238f7ef Reviewed-on: https://go-review.googlesource.com/5421 Reviewed-by: Russ Cox <rsc@golang.org>
-rw-r--r--src/cmd/asm/internal/asm/asm.go6
-rw-r--r--src/cmd/asm/internal/asm/endtoend_test.go77
-rw-r--r--src/cmd/asm/internal/asm/operand_test.go11
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm.out54
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm.s276
-rw-r--r--src/cmd/asm/internal/asm/testdata/ppc64.out110
-rw-r--r--src/cmd/asm/internal/asm/testdata/ppc64.s709
-rw-r--r--src/cmd/asm/internal/lex/lex.go5
8 files changed, 1246 insertions, 2 deletions
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 5d0d080190..f0cf117f05 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -5,6 +5,7 @@
package asm
import (
+ "bytes"
"fmt"
"text/scanner"
@@ -18,6 +19,8 @@ import (
// TODO: configure the architecture
+var testOut *bytes.Buffer // Gathers output when testing.
+
// append adds the Prog to the end of the program-thus-far.
// If doLabel is set, it also defines the labels collect for this Prog.
func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
@@ -46,6 +49,9 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
if *flags.Debug {
fmt.Println(p.histLineNum, prog)
}
+ if testOut != nil {
+ fmt.Fprintln(testOut, p.histLineNum, prog)
+ }
}
// validateSymbol checks that addr represents a valid name for a pseudo-op.
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
new file mode 100644
index 0000000000..270f80d0f6
--- /dev/null
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -0,0 +1,77 @@
+// Copyright 2015 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 asm
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "cmd/asm/internal/lex"
+ "cmd/internal/obj"
+)
+
+// An end-to-end test for the assembler: Do we print what we parse?
+// Output is generated by, in effect, turning on -S and comparing the
+// result against a golden file.
+
+func testEndToEnd(t *testing.T, goarch string) {
+ lex.InitHist()
+ input := filepath.Join("testdata", goarch+".s")
+ output := filepath.Join("testdata", goarch+".out")
+ architecture, ctxt := setArch(goarch)
+ lexer := lex.NewLexer(input, ctxt)
+ parser := NewParser(ctxt, architecture, lexer)
+ pList := obj.Linknewplist(ctxt)
+ var ok bool
+ testOut = new(bytes.Buffer) // The assembler writes -S output to this buffer.
+ ctxt.Bso = obj.Binitw(os.Stdout)
+ defer obj.Bflush(ctxt.Bso)
+ ctxt.Diag = log.Fatalf
+ obj.Binitw(ioutil.Discard)
+ pList.Firstpc, ok = parser.Parse()
+ if !ok {
+ t.Fatalf("asm: ppc64 assembly failed")
+ }
+ result := string(testOut.Bytes())
+ expect, err := ioutil.ReadFile(output)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if result != string(expect) {
+ if false { // Enable to capture output.
+ fmt.Printf("%s", result)
+ os.Exit(1)
+ }
+ t.Errorf("%s failed: output differs", goarch)
+ r := strings.Split(result, "\n")
+ e := strings.Split(string(expect), "\n")
+ if len(r) != len(e) {
+ t.Errorf("%s: expected %d lines, got %d", len(e), len(r))
+ }
+ n := len(e)
+ if n > len(r) {
+ n = len(r)
+ }
+ for i := 0; i < n; i++ {
+ if r[i] != e[i] {
+ t.Errorf("%s:%d:\nexpected\n\t%s\ngot\n\t%s", output, i, e[i], r[i])
+ }
+ }
+ }
+}
+
+func TestPPC64EndToEnd(t *testing.T) {
+ testEndToEnd(t, "ppc64")
+}
+
+func TestARMEndToEnd(t *testing.T) {
+ testEndToEnd(t, "arm")
+}
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index 4437b7d5a6..1c4d983cf9 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -15,10 +15,17 @@ import (
// A simple in-out test: Do we print what we parse?
-func newParser(goarch string) *Parser {
+func setArch(goarch string) (*arch.Arch, *obj.Link) {
os.Setenv("GOOS", "linux") // obj can handle this OS for all architectures.
architecture := arch.Set(goarch)
- ctxt := obj.Linknew(architecture.LinkArch)
+ if architecture == nil {
+ panic("asm: unrecognized architecture " + goarch)
+ }
+ return architecture, obj.Linknew(architecture.LinkArch)
+}
+
+func newParser(goarch string) *Parser {
+ architecture, ctxt := setArch(goarch)
return NewParser(ctxt, architecture, nil)
}
diff --git a/src/cmd/asm/internal/asm/testdata/arm.out b/src/cmd/asm/internal/asm/testdata/arm.out
new file mode 100644
index 0000000000..af0b4638e5
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/arm.out
@@ -0,0 +1,54 @@
+1 00001 (testdata/arm.s:1) TEXT foo+0(SB),0,$0
+10 00002 (testdata/arm.s:10) ADD $1,R2,R3
+11 00003 (testdata/arm.s:11) ADD R1<<R2,R3,R4
+12 00004 (testdata/arm.s:12) ADD R1>>R2,R3,R4
+13 00005 (testdata/arm.s:13) ADD R1@>R2,R3,R4
+14 00006 (testdata/arm.s:14) ADD R1->R2,R3,R4
+15 00007 (testdata/arm.s:15) ADD R1,R2,R3
+16 00008 (testdata/arm.s:16) ADD R1<<R2,R3,R4
+26 00009 (testdata/arm.s:26) ADD $1,R2
+27 00010 (testdata/arm.s:27) ADD R1<<R2,R3
+28 00011 (testdata/arm.s:28) ADD R1>>R2,R3
+29 00012 (testdata/arm.s:29) ADD R1@>R2,R3
+30 00013 (testdata/arm.s:30) ADD R1->R2,R3
+31 00014 (testdata/arm.s:31) ADD R1,R2
+40 00015 (testdata/arm.s:40) CLZ.S R1,R2
+49 00016 (testdata/arm.s:49) MOVW.S R1,R2
+50 00017 (testdata/arm.s:50) MOVW.S $1,R2
+51 00018 (testdata/arm.s:51) MOVW.S R1<<R2,R3
+60 00019 (testdata/arm.s:60) JMP.S ,20(PC)
+66 00020 (testdata/arm.s:66) JMP.S ,0(R2)
+67 00021 (testdata/arm.s:67) JMP.S ,foo+0(SB)
+68 00022 (testdata/arm.s:68) JMP.S ,bar<>+0(SB)
+77 00023 (testdata/arm.s:77) BX 0(R2),
+86 00024 (testdata/arm.s:86) BEQ ,25(PC)
+95 00025 (testdata/arm.s:95) SWI.S ,R1
+96 00026 (testdata/arm.s:96) SWI.S ,0(R1)
+97 00027 (testdata/arm.s:97) SWI.S ,foo+0(SB)
+106 00028 (testdata/arm.s:106) CMP.S $1,R2,
+107 00029 (testdata/arm.s:107) CMP.S R1<<R2,R3,
+108 00030 (testdata/arm.s:108) CMP.S R1,R2,
+122 00031 (testdata/arm.s:122) MOVM 0(R1),[R2,R5,R8,R10]
+123 00032 (testdata/arm.s:123) MOVM 0(R1),[R2,R3,R4,R5]
+124 00033 (testdata/arm.s:124) MOVM.S 0(R1),[R2]
+135 00034 (testdata/arm.s:135) MOVM [R2,R5,R8,R10],0(R1)
+136 00035 (testdata/arm.s:136) MOVM [R2,R3,R4,R5],0(R1)
+137 00036 (testdata/arm.s:137) MOVM.S [R2],0(R1)
+146 00037 (testdata/arm.s:146) STREX.S 0(R2),R1,R3
+152 00038 (testdata/arm.s:152) STREX.S 0(R2),R1,R1
+158 00039 (testdata/arm.s:158) STREX.S 0(R2),R3,R3
+166 00040 (testdata/arm.s:166) CASE.S R1,
+175 00041 (testdata/arm.s:175) WORD ,$1234
+184 00042 (testdata/arm.s:184) ABSF.S F1,F2
+190 00043 (testdata/arm.s:190) ADDD.S F1,F2
+191 00044 (testdata/arm.s:191) ADDD.S $0.5,F2
+197 00045 (testdata/arm.s:197) ADDD.S F1,F2,F3
+198 00046 (testdata/arm.s:198) ADDD.S $0.5,F2,F3
+204 00047 (testdata/arm.s:204) CMPD.S F1,F2
+228 00048 (testdata/arm.s:228) MRC ,$8301712627
+237 00049 (testdata/arm.s:237) MULL R1,R2,(R3, R4)
+249 00050 (testdata/arm.s:249) MULAWT R1,R2,R3, R4
+257 00051 (testdata/arm.s:257) PLD 0(R1),
+258 00052 (testdata/arm.s:258) PLD 4(R1),
+267 00053 (testdata/arm.s:267) RET ,
+276 00054 (testdata/arm.s:276) END ,
diff --git a/src/cmd/asm/internal/asm/testdata/arm.s b/src/cmd/asm/internal/asm/testdata/arm.s
new file mode 100644
index 0000000000..184ed9fc3c
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/arm.s
@@ -0,0 +1,276 @@
+TEXT foo(SB), 0, $0
+
+// ADD
+//
+// LTYPE1 cond imsr ',' spreg ',' reg
+// {
+// outcode($1, $2, &$3, $5, &$7);
+// }
+// Cover some operand space here too.
+ ADD $1, R2, R3
+ ADD R1<<R2, R3, R4
+ ADD R1>>R2, R3, R4
+ ADD R1@>R2, R3, R4
+ ADD R1->R2, R3, R4
+ ADD R1, R2, R3
+ ADD R(1)<<R(2), R(3), R(4)
+
+// LTYPE1 cond imsr ',' spreg ',' // asm doesn't support trailing comma.
+// {
+// outcode($1, $2, &$3, $5, &nullgen);
+// }
+// LTYPE1 cond imsr ',' reg
+// {
+// outcode($1, $2, &$3, 0, &$5);
+// }
+ ADD $1, R2
+ ADD R1<<R2, R3
+ ADD R1>>R2, R3
+ ADD R1@>R2, R3
+ ADD R1->R2, R3
+ ADD R1, R2
+
+//
+// MVN
+//
+// LTYPE2 cond imsr ',' reg
+// {
+// outcode($1, $2, &$3, 0, &$5);
+// }
+ CLZ.S R1, R2
+
+//
+// MOVW
+//
+// LTYPE3 cond gen ',' gen
+// {
+// outcode($1, $2, &$3, 0, &$5);
+// }
+ MOVW.S R1, R2
+ MOVW.S $1, R2
+ MOVW.S R1<<R2, R3
+
+//
+// B/BL
+//
+// LTYPE4 cond comma rel
+// {
+// outcode($1, $2, &nullgen, 0, &$4);
+// }
+ B.S 1(PC)
+
+// LTYPE4 cond comma nireg
+// {
+// outcode($1, $2, &nullgen, 0, &$4);
+// }
+ B.S (R2)
+ B.S foo(SB)
+ B.S bar<>(SB)
+
+//
+// BX
+//
+// LTYPEBX comma ireg
+// {
+// outcode($1, Always, &nullgen, 0, &$3);
+// }
+ BX (R2)
+
+//
+// BEQ
+//
+// LTYPE5 comma rel
+// {
+// outcode($1, Always, &nullgen, 0, &$3);
+// }
+ BEQ 1(PC)
+
+//
+// SWI
+//
+// LTYPE6 cond comma gen
+// {
+// outcode($1, $2, &nullgen, 0, &$4);
+// }
+ SWI.S R1
+ SWI.S (R1)
+ SWI.S foo(SB)
+
+//
+// CMP
+//
+// LTYPE7 cond imsr ',' spreg
+// {
+// outcode($1, $2, &$3, $5, &nullgen);
+// }
+ CMP.S $1, R2
+ CMP.S R1<<R2, R3
+ CMP.S R1, R2
+
+//
+// MOVM
+//
+// LTYPE8 cond ioreg ',' '[' reglist ']'
+// {
+// var g obj.Addr
+//
+// g = nullgen;
+// g.Type = obj.TYPE_CONST;
+// g.Offset = int64($6);
+// outcode($1, $2, &$3, 0, &g);
+// }
+ MOVM 0(R1), [R2,R5,R8,g]
+ MOVM 0(R1), [R2-R5]
+ MOVM.S (R1), [R2]
+
+// LTYPE8 cond '[' reglist ']' ',' ioreg
+// {
+// var g obj.Addr
+//
+// g = nullgen;
+// g.Type = obj.TYPE_CONST;
+// g.Offset = int64($4);
+// outcode($1, $2, &g, 0, &$7);
+// }
+ MOVM [R2,R5,R8,g], 0(R1)
+ MOVM [R2-R5], 0(R1)
+ MOVM.S [R2], (R1)
+
+//
+// SWAP
+//
+// LTYPE9 cond reg ',' ireg ',' reg
+// {
+// outcode($1, $2, &$5, int32($3.Reg), &$7);
+// }
+ STREX.S R1, (R2), R3
+
+// LTYPE9 cond reg ',' ireg
+// {
+// outcode($1, $2, &$5, int32($3.Reg), &$3);
+// }
+ STREX.S R1, (R2)
+
+// LTYPE9 cond comma ireg ',' reg
+// {
+// outcode($1, $2, &$4, int32($6.Reg), &$6);
+// }
+ STREX.S (R2), R3
+
+// CASE
+//
+// LTYPED cond reg
+// {
+// outcode($1, $2, &$3, 0, &nullgen);
+// }
+ CASE.S R1
+
+//
+// word
+//
+// LTYPEH comma ximm
+// {
+// outcode($1, Always, &nullgen, 0, &$3);
+// }
+ WORD $1234
+
+//
+// floating-point coprocessor
+//
+// LTYPEI cond freg ',' freg
+// {
+// outcode($1, $2, &$3, 0, &$5);
+// }
+ ABSF.S F1, F2
+
+// LTYPEK cond frcon ',' freg
+// {
+// outcode($1, $2, &$3, 0, &$5);
+// }
+ ADDD.S F1, F2
+ ADDD.S $0.5, F2
+
+// LTYPEK cond frcon ',' LFREG ',' freg
+// {
+// outcode($1, $2, &$3, $5, &$7);
+// }
+ ADDD.S F1, F2, F3
+ ADDD.S $0.5, F2, F3
+
+// LTYPEL cond freg ',' freg
+// {
+// outcode($1, $2, &$3, int32($5.Reg), &nullgen);
+// }
+ CMPD.S F1, F2
+
+//
+// MCR MRC
+//
+// LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
+// {
+// var g obj.Addr
+//
+// g = nullgen;
+// g.Type = obj.TYPE_CONST;
+// g.Offset = int64(
+// (0xe << 24) | /* opcode */
+// ($1 << 20) | /* MCR/MRC */
+// (($2^C_SCOND_XOR) << 28) | /* scond */
+// (($3 & 15) << 8) | /* coprocessor number */
+// (($5 & 7) << 21) | /* coprocessor operation */
+// (($7 & 15) << 12) | /* arm register */
+// (($9 & 15) << 16) | /* Crn */
+// (($11 & 15) << 0) | /* Crm */
+// (($12 & 7) << 5) | /* coprocessor information */
+// (1<<4)); /* must be set */
+// outcode(AMRC, Always, &nullgen, 0, &g);
+// }
+ MRC.S 4, 6, R1, C2, C3, 7
+
+//
+// MULL r1,r2,(hi,lo)
+//
+// LTYPEM cond reg ',' reg ',' regreg
+// {
+// outcode($1, $2, &$3, int32($5.Reg), &$7);
+// }
+ MULL R1, R2, (R3,R4)
+
+//
+// MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff . r4
+// MULAW{T,B} r1,r2,r3,r4
+//
+// LTYPEN cond reg ',' reg ',' reg ',' spreg
+// {
+// $7.Type = obj.TYPE_REGREG2;
+// $7.Offset = int64($9);
+// outcode($1, $2, &$3, int32($5.Reg), &$7);
+// }
+ MULAWT R1, R2, R3, R4
+//
+// PLD
+//
+// LTYPEPLD oreg
+// {
+// outcode($1, Always, &$2, 0, &nullgen);
+// }
+ PLD (R1)
+ PLD 4(R1)
+
+//
+// RET
+//
+// LTYPEA cond
+// {
+// outcode($1, $2, &nullgen, 0, &nullgen);
+// }
+ RET
+
+//
+// END
+//
+// LTYPEE
+// {
+// outcode($1, Always, &nullgen, 0, &nullgen);
+// }
+ END
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.out b/src/cmd/asm/internal/asm/testdata/ppc64.out
new file mode 100644
index 0000000000..50bca559e5
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.out
@@ -0,0 +1,110 @@
+5 00001 (testdata/ppc64.s:5) TEXT foo(SB),$0
+15 00002 (testdata/ppc64.s:15) MOVW R1,R2
+21 00003 (testdata/ppc64.s:21) MOVW foo<>+3(SB),R2
+22 00004 (testdata/ppc64.s:22) MOVW 16(R1),R2
+28 00005 (testdata/ppc64.s:28) MOVW 0(R1),R2
+29 00006 (testdata/ppc64.s:29) MOVW 0(R1+R2),R3
+35 00007 (testdata/ppc64.s:35) MOVW R1,R2
+41 00008 (testdata/ppc64.s:41) MOVB foo<>+3(SB),R2
+42 00009 (testdata/ppc64.s:42) MOVB 16(R1),R2
+48 00010 (testdata/ppc64.s:48) MOVB 0(R1),R2
+49 00011 (testdata/ppc64.s:49) MOVB 0(R1+R2),R3
+58 00012 (testdata/ppc64.s:58) FMOVD foo<>+3(SB),F2
+59 00013 (testdata/ppc64.s:59) FMOVD 16(R1),F2
+65 00014 (testdata/ppc64.s:65) FMOVD 0(R1),F2
+71 00015 (testdata/ppc64.s:71) FMOVD $0.10000000000000001,F2
+77 00016 (testdata/ppc64.s:77) FMOVD F1,F2
+83 00017 (testdata/ppc64.s:83) FMOVD F2,foo<>+3(SB)
+84 00018 (testdata/ppc64.s:84) FMOVD F2,16(R1)
+90 00019 (testdata/ppc64.s:90) FMOVD F2,0(R1)
+99 00020 (testdata/ppc64.s:99) MOVW R1,foo<>+3(SB)
+100 00021 (testdata/ppc64.s:100) MOVW R1,16(R2)
+106 00022 (testdata/ppc64.s:106) MOVW R1,0(R1)
+107 00023 (testdata/ppc64.s:107) MOVW R1,0(R2+R3)
+113 00024 (testdata/ppc64.s:113) MOVB R1,foo<>+3(SB)
+114 00025 (testdata/ppc64.s:114) MOVB R1,16(R2)
+120 00026 (testdata/ppc64.s:120) MOVB R1,0(R1)
+121 00027 (testdata/ppc64.s:121) MOVB R1,0(R2+R3)
+129 00028 (testdata/ppc64.s:129) FMOVD F1,foo<>+3(SB)
+130 00029 (testdata/ppc64.s:130) FMOVD F1,16(R2)
+136 00030 (testdata/ppc64.s:136) FMOVD F1,0(R1)
+145 00031 (testdata/ppc64.s:145) MOVFL FPSCR,F1
+151 00032 (testdata/ppc64.s:151) MOVFL F1,FPSCR
+157 00033 (testdata/ppc64.s:157) MOVFL F1,$4,FPSCR
+163 00034 (testdata/ppc64.s:163) MOVFL FPSCR,C0
+184 00035 (testdata/ppc64.s:184) MOVW R1,C1
+190 00036 (testdata/ppc64.s:190) MOVW R1,CR
+202 00037 (testdata/ppc64.s:202) ADD R1,R2,R3
+208 00038 (testdata/ppc64.s:208) ADD $1,R2,R3
+220 00039 (testdata/ppc64.s:220) ADD R1,R2
+226 00040 (testdata/ppc64.s:226) ADD $4,R1
+232 00041 (testdata/ppc64.s:232) ADDE R1,R2,R3
+238 00042 (testdata/ppc64.s:238) ADDE R1,R2
+244 00043 (testdata/ppc64.s:244) SLW R1,R2,R3
+250 00044 (testdata/ppc64.s:250) SLW R1,R2
+256 00045 (testdata/ppc64.s:256) SLW $4,R1,R2
+262 00046 (testdata/ppc64.s:262) SLW $4,R1
+268 00047 (testdata/ppc64.s:268) SLW $4,R1
+274 00048 (testdata/ppc64.s:274) SUBME R1,R1
+292 00049 (testdata/ppc64.s:292) MOVW $1,R1
+298 00050 (testdata/ppc64.s:298) MOVW $1,R1
+299 00051 (testdata/ppc64.s:299) MOVW $foo(SB),R1
+323 00052 (testdata/ppc64.s:323) MOVFL C0,C1
+335 00053 (testdata/ppc64.s:335) MOVW CR,R1
+341 00054 (testdata/ppc64.s:341) MOVW SPR(0),R1
+342 00055 (testdata/ppc64.s:342) MOVW SPR(7),R1
+348 00056 (testdata/ppc64.s:348) MOVW LR,R1
+349 00057 (testdata/ppc64.s:349) MOVW CTR,R1
+355 00058 (testdata/ppc64.s:355) MOVW R1,LR
+356 00059 (testdata/ppc64.s:356) MOVW R1,CTR
+368 00060 (testdata/ppc64.s:368) MOVW R1,SPR(7)
+380 00061 (testdata/ppc64.s:380) JMP ,62(APC)
+381 00062 (testdata/ppc64.s:381) JMP ,61
+387 00063 (testdata/ppc64.s:387) JMP ,4(R1)
+388 00064 (testdata/ppc64.s:388) JMP ,foo(SB)
+394 00065 (testdata/ppc64.s:394) JMP ,CTR
+413 00066 (testdata/ppc64.s:413) BEQ C1,67(APC)
+414 00067 (testdata/ppc64.s:414) BEQ C1,66
+440 00068 (testdata/ppc64.s:440) BC 4,CTR
+450 00069 (testdata/ppc64.s:450) BC $3,R4,66
+470 00070 (testdata/ppc64.s:470) BC $3,R3,LR
+500 00071 (testdata/ppc64.s:500) FABS F1,F2
+506 00072 (testdata/ppc64.s:506) FADD F1,F2
+512 00073 (testdata/ppc64.s:512) FADD F1,F2,F3
+518 00074 (testdata/ppc64.s:518) FMADD F1,F2,F3,F4
+524 00075 (testdata/ppc64.s:524) FCMPU F1,F2
+530 00076 (testdata/ppc64.s:530) FCMPU F1,F2,C0
+539 00077 (testdata/ppc64.s:539) CMP R1,R2
+545 00078 (testdata/ppc64.s:545) CMP R1,$4
+551 00079 (testdata/ppc64.s:551) CMP R1,C0,R2
+557 00080 (testdata/ppc64.s:557) CMP R1,C0,$4
+566 00081 (testdata/ppc64.s:566) RLDC $4,R1,$5,R2
+572 00082 (testdata/ppc64.s:572) RLDC $26,R1,$201326592,R2
+578 00083 (testdata/ppc64.s:578) RLDC R1,R2,$4,R3
+584 00084 (testdata/ppc64.s:584) RLWMI R1,R2,$201326592,R3
+593 00085 (testdata/ppc64.s:593) MOVMW foo(SB),R2
+594 00086 (testdata/ppc64.s:594) MOVMW 4(R1),R2
+600 00087 (testdata/ppc64.s:600) MOVMW R1,foo(SB)
+601 00088 (testdata/ppc64.s:601) MOVMW R1,4(R2)
+611 00089 (testdata/ppc64.s:611) LSW 0(R1),R2
+612 00090 (testdata/ppc64.s:612) LSW 0(R1+R2),R3
+618 00091 (testdata/ppc64.s:618) LSW 0(R1+NONE),R2
+619 00092 (testdata/ppc64.s:619) LSW 0(R1+NONE),R3
+625 00093 (testdata/ppc64.s:625) STSW R1,0(R2)
+626 00094 (testdata/ppc64.s:626) STSW R1,0(R2+R3)
+632 00095 (testdata/ppc64.s:632) STSW R1,0(R2+NONE)
+633 00096 (testdata/ppc64.s:633) STSW R1,0(R2+NONE)
+639 00097 (testdata/ppc64.s:639) MOVHBR 0(R1),R2
+640 00098 (testdata/ppc64.s:640) MOVHBR 0(R1+R2),R3
+646 00099 (testdata/ppc64.s:646) MOVHBR R1,0(R2)
+647 00100 (testdata/ppc64.s:647) MOVHBR R1,0(R2+R3)
+653 00101 (testdata/ppc64.s:653) DCBF 0(R1),
+654 00102 (testdata/ppc64.s:654) DCBF 0(R1),
+663 00103 (testdata/ppc64.s:663) NOP ,
+669 00104 (testdata/ppc64.s:669) NOP R2,
+675 00105 (testdata/ppc64.s:675) NOP F2,
+681 00106 (testdata/ppc64.s:681) NOP R2,
+687 00107 (testdata/ppc64.s:687) NOP F2,
+693 00108 (testdata/ppc64.s:693) NOP $4,
+701 00109 (testdata/ppc64.s:701) RET ,
+709 00110 (testdata/ppc64.s:709) END ,
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
new file mode 100644
index 0000000000..1fb53982c1
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -0,0 +1,709 @@
+// This input was created by taking the instruction productions in
+// the old assembler's (9a's) grammar and hand-writing one complete
+// instruction for each rule, to guarantee we cover the same space.
+
+TEXT foo(SB),0,$0
+
+//inst:
+//
+// load ints and bytes
+//
+// LMOVW rreg ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW R1, R2
+
+// LMOVW addr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW foo<>+3(SB), R2
+ MOVW 16(R1), R2
+
+// LMOVW regaddr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW (R1), R2
+ MOVW (R1+R2), R3
+
+// LMOVB rreg ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW R1, R2
+
+// LMOVB addr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVB foo<>+3(SB), R2
+ MOVB 16(R1), R2
+
+// LMOVB regaddr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVB (R1), R2
+ MOVB (R1+R2), R3
+
+//
+// load floats
+//
+// LFMOV addr ',' freg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FMOVD foo<>+3(SB), F2
+ FMOVD 16(R1), F2
+
+// LFMOV regaddr ',' freg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FMOVD (R1), F2
+
+// LFMOV fimm ',' freg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FMOVD $0.1, F2
+
+// LFMOV freg ',' freg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FMOVD F1, F2
+
+// LFMOV freg ',' addr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FMOVD F2, foo<>+3(SB)
+ FMOVD F2, 16(R1)
+
+// LFMOV freg ',' regaddr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FMOVD F2, (R1)
+
+//
+// store ints and bytes
+//
+// LMOVW rreg ',' addr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW R1, foo<>+3(SB)
+ MOVW R1, 16(R2)
+
+// LMOVW rreg ',' regaddr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW R1, (R1)
+ MOVW R1, (R2+R3)
+
+// LMOVB rreg ',' addr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVB R1, foo<>+3(SB)
+ MOVB R1, 16(R2)
+
+// LMOVB rreg ',' regaddr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVB R1, (R1)
+ MOVB R1, (R2+R3)
+//
+// store floats
+//
+// LMOVW freg ',' addr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FMOVD F1, foo<>+3(SB)
+ FMOVD F1, 16(R2)
+
+// LMOVW freg ',' regaddr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FMOVD F1, (R1)
+
+//
+// floating point status
+//
+// LMOVW fpscr ',' freg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVFL FPSCR, F1
+
+// LMOVW freg ',' fpscr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVFL F1, FPSCR
+
+// LMOVW freg ',' imm ',' fpscr
+// {
+// outgcode(int($1), &$2, 0, &$4, &$6);
+// }
+ MOVFL F1, $4, FPSCR
+
+// LMOVW fpscr ',' creg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVFL FPSCR, CR0
+
+// LMTFSB imm ',' con
+// {
+// outcode(int($1), &$2, int($4), &nullgen);
+// }
+//TODO 9a doesn't work MTFSB0 $4, 4
+
+//
+// field moves (mtcrf)
+//
+// LMOVW rreg ',' imm ',' lcr
+// {
+// outgcode(int($1), &$2, 0, &$4, &$6);
+// }
+// TODO 9a doesn't work MOVFL R1,$4,CR
+
+// LMOVW rreg ',' creg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW R1, CR1
+
+// LMOVW rreg ',' lcr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW R1, CR
+
+//
+// integer operations
+// logical instructions
+// shift instructions
+// unary instructions
+//
+// LADDW rreg ',' sreg ',' rreg
+// {
+// outcode(int($1), &$2, int($4), &$6);
+// }
+ ADD R1, R2, R3
+
+// LADDW imm ',' sreg ',' rreg
+// {
+// outcode(int($1), &$2, int($4), &$6);
+// }
+ ADD $1, R2, R3
+
+// LADDW rreg ',' imm ',' rreg
+// {
+// outgcode(int($1), &$2, 0, &$4, &$6);
+// }
+//TODO 9a trouble ADD R1, $2, R3 maybe swap rreg and imm
+
+// LADDW rreg ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ ADD R1, R2
+
+// LADDW imm ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ ADD $4, R1
+
+// LLOGW rreg ',' sreg ',' rreg
+// {
+// outcode(int($1), &$2, int($4), &$6);
+// }
+ ADDE R1, R2, R3
+
+// LLOGW rreg ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ ADDE R1, R2
+
+// LSHW rreg ',' sreg ',' rreg
+// {
+// outcode(int($1), &$2, int($4), &$6);
+// }
+ SLW R1, R2, R3
+
+// LSHW rreg ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ SLW R1, R2
+
+// LSHW imm ',' sreg ',' rreg
+// {
+// outcode(int($1), &$2, int($4), &$6);
+// }
+ SLW $4, R1, R2
+
+// LSHW imm ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ SLW $4, R1
+
+// LABS rreg ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ SLW $4, R1
+
+// LABS rreg
+// {
+// outcode(int($1), &$2, 0, &$2);
+// }
+ SUBME R1
+
+//
+// multiply-accumulate
+//
+// LMA rreg ',' sreg ',' rreg
+// {
+// outcode(int($1), &$2, int($4), &$6);
+// }
+//TODO this instruction is undefined in lex.go LMA R1, R2, R3 NOT SUPPORTED (called MAC)
+
+//
+// move immediate: macro for cau+or, addi, addis, and other combinations
+//
+// LMOVW imm ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW $1, R1
+
+// LMOVW ximm ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW $1, R1
+ MOVW $foo(SB), R1
+
+// condition register operations
+//
+// LCROP cbit ',' cbit
+// {
+// outcode(int($1), &$2, int($4.Reg), &$4);
+// }
+//TODO 9a trouble CREQV 1, 2 delete? liblink encodes like a divide (maybe wrong too)
+
+// LCROP cbit ',' con ',' cbit
+// {
+// outcode(int($1), &$2, int($4), &$6);
+// }
+//TODO 9a trouble CREQV 1, 2, 3
+
+//
+// condition register moves
+// move from machine state register
+//
+// LMOVW creg ',' creg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVFL CR0, CR1
+
+// LMOVW psr ',' creg // TODO: should psr should be fpscr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+//TODO 9a trouble MOVW FPSCR, CR1
+
+// LMOVW lcr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW CR, R1
+
+// LMOVW psr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW SPR(0), R1
+ MOVW SPR(7), R1
+
+// LMOVW xlreg ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW LR, R1
+ MOVW CTR, R1
+
+// LMOVW rreg ',' xlreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW R1, LR
+ MOVW R1, CTR
+
+// LMOVW creg ',' psr // TODO doesn't exist
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+//TODO 9a trouble MOVW CR1, SPR(7)
+
+// LMOVW rreg ',' psr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVW R1, SPR(7)
+
+//
+// branch, branch conditional
+// branch conditional register
+// branch conditional to count register
+//
+// LBRA rel
+// {
+// outcode(int($1), &nullgen, 0, &$2);
+// }
+label0:
+ BR 1(PC)
+ BR label0+0
+
+// LBRA addr
+// {
+// outcode(int($1), &nullgen, 0, &$2);
+// }
+ BR 4(R1)
+ BR foo+0(SB)
+
+// LBRA '(' xlreg ')'
+// {
+// outcode(int($1), &nullgen, 0, &$3);
+// }
+ BR (CTR)
+
+// LBRA ',' rel // asm doesn't support the leading comma
+// {
+// outcode(int($1), &nullgen, 0, &$3);
+// }
+// LBRA ',' addr // asm doesn't support the leading comma
+// {
+// outcode(int($1), &nullgen, 0, &$3);
+// }
+// LBRA ',' '(' xlreg ')' // asm doesn't support the leading comma
+// {
+// outcode(int($1), &nullgen, 0, &$4);
+// }
+// LBRA creg ',' rel
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+label1:
+ BEQ CR1, 1(PC)
+ BEQ CR1, label1
+
+// LBRA creg ',' addr // TODO DOES NOT WORK in 9a
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+
+// LBRA creg ',' '(' xlreg ')' // TODO DOES NOT WORK in 9a
+// {
+// outcode(int($1), &$2, 0, &$5);
+// }
+
+// LBRA con ',' rel // TODO DOES NOT WORK in 9a
+// {
+// outcode(int($1), &nullgen, int($2), &$4);
+// }
+
+// LBRA con ',' addr // TODO DOES NOT WORK in 9a
+// {
+// outcode(int($1), &nullgen, int($2), &$4);
+// }
+
+// LBRA con ',' '(' xlreg ')'
+// {
+// outcode(int($1), &nullgen, int($2), &$5);
+// }
+ BC 4, (CTR)
+
+// LBRA con ',' con ',' rel
+// {
+// var g obj.Addr
+// g = nullgen;
+// g.Type = obj.TYPE_CONST;
+// g.Offset = $2;
+// outcode(int($1), &g, int(REG_R0+$4), &$6);
+// }
+ BC 3, 4, label1
+
+// LBRA con ',' con ',' addr // TODO mystery
+// {
+// var g obj.Addr
+// g = nullgen;
+// g.Type = obj.TYPE_CONST;
+// g.Offset = $2;
+// outcode(int($1), &g, int(REG_R0+$4), &$6);
+// }
+//TODO 9a trouble BC 3, 3, 4(R1)
+
+// LBRA con ',' con ',' '(' xlreg ')'
+// {
+// var g obj.Addr
+// g = nullgen;
+// g.Type = obj.TYPE_CONST;
+// g.Offset = $2;
+// outcode(int($1), &g, int(REG_R0+$4), &$7);
+// }
+ BC 3, 3, (LR)
+
+//
+// conditional trap // TODO NOT DEFINED
+// TODO these instructions are not in lex.go
+//
+// LTRAP rreg ',' sreg
+// {
+// outcode(int($1), &$2, int($4), &nullgen);
+// }
+// LTRAP imm ',' sreg
+// {
+// outcode(int($1), &$2, int($4), &nullgen);
+// }
+// LTRAP rreg comma
+// {
+// outcode(int($1), &$2, 0, &nullgen);
+// }
+// LTRAP comma
+// {
+// outcode(int($1), &nullgen, 0, &nullgen);
+// }
+
+//
+// floating point operate
+//
+// LFCONV freg ',' freg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FABS F1, F2
+
+// LFADD freg ',' freg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FADD F1, F2
+
+// LFADD freg ',' freg ',' freg
+// {
+// outcode(int($1), &$2, int($4.Reg), &$6);
+// }
+ FADD F1, F2, F3
+
+// LFMA freg ',' freg ',' freg ',' freg
+// {
+// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+// }
+ FMADD F1, F2, F3, F4
+
+// LFCMP freg ',' freg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ FCMPU F1, F2
+
+// LFCMP freg ',' freg ',' creg
+// {
+// outcode(int($1), &$2, int($6.Reg), &$4);
+// }
+ FCMPU F1, F2, CR0
+
+//
+// CMP
+//
+// LCMP rreg ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ CMP R1, R2
+
+// LCMP rreg ',' imm
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ CMP R1, $4
+
+// LCMP rreg ',' rreg ',' creg
+// {
+// outcode(int($1), &$2, int($6.Reg), &$4);
+// }
+ CMP R1, R2, CR0
+
+// LCMP rreg ',' imm ',' creg
+// {
+// outcode(int($1), &$2, int($6.Reg), &$4);
+// }
+ CMP R1, $4, CR0
+
+//
+// rotate and mask
+//
+// LRLWM imm ',' rreg ',' imm ',' rreg
+// {
+// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+// }
+ RLDC $4, R1, $5, R2
+
+// LRLWM imm ',' rreg ',' mask ',' rreg
+// {
+// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+// }
+ RLDC $26, R1, 4, 5, R2
+
+// LRLWM rreg ',' rreg ',' imm ',' rreg
+// {
+// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+// }
+ RLDC R1, R2, $4, R3
+
+// LRLWM rreg ',' rreg ',' mask ',' rreg
+// {
+// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+// }
+ RLWMI R1, R2, 4, 5, R3
+
+//
+// load/store multiple
+//
+// LMOVMW addr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVMW foo+0(SB), R2
+ MOVMW 4(R1), R2
+
+// LMOVMW rreg ',' addr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVMW R1, foo+0(SB)
+ MOVMW R1, 4(R2)
+
+//
+// various indexed load/store
+// indexed unary (eg, cache clear)
+//
+// LXLD regaddr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ LSW (R1), R2
+ LSW (R1+R2), R3
+
+// LXLD regaddr ',' imm ',' rreg
+// {
+// outgcode(int($1), &$2, 0, &$4, &$6);
+// }
+ LSW (R1), $1, R2
+ LSW (R1+R2), $1, R3
+
+// LXST rreg ',' regaddr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ STSW R1, (R2)
+ STSW R1, (R2+R3)
+
+// LXST rreg ',' imm ',' regaddr
+// {
+// outgcode(int($1), &$2, 0, &$4, &$6);
+// }
+ STSW R1, $1, (R2)
+ STSW R1, $1, (R2+R3)
+
+// LXMV regaddr ',' rreg
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVHBR (R1), R2
+ MOVHBR (R1+R2), R3
+
+// LXMV rreg ',' regaddr
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+ MOVHBR R1, (R2)
+ MOVHBR R1, (R2+R3)
+
+// LXOP regaddr
+// {
+// outcode(int($1), &$2, 0, &nullgen);
+// }
+ DCBF (R1)
+ DCBF (R1+R2)
+
+//
+// NOP
+//
+// LNOP comma // asm doesn't support the trailing comma.
+// {
+// outcode(int($1), &nullgen, 0, &nullgen);
+// }
+ NOP
+
+// LNOP rreg comma // asm doesn't support the trailing comma.
+// {
+// outcode(int($1), &$2, 0, &nullgen);
+// }
+ NOP R2
+
+// LNOP freg comma // asm doesn't support the trailing comma.
+// {
+// outcode(int($1), &$2, 0, &nullgen);
+// }
+ NOP F2
+
+// LNOP ',' rreg // asm doesn't support the leading comma.
+// {
+// outcode(int($1), &nullgen, 0, &$3);
+// }
+ NOP R2
+
+// LNOP ',' freg // asm doesn't support the leading comma.
+// {
+// outcode(int($1), &nullgen, 0, &$3);
+// }
+ NOP F2
+
+// LNOP imm // SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards.
+// {
+// outcode(int($1), &$2, 0, &nullgen);
+// }
+ NOP $4
+
+// RETURN
+//
+// LRETRN comma // asm doesn't support the trailing comma.
+// {
+// outcode(int($1), &nullgen, 0, &nullgen);
+// }
+ RETURN
+
+// END
+//
+// LEND comma // asm doesn't support the trailing comma.
+// {
+// outcode(int($1), &nullgen, 0, &nullgen);
+// }
+ END
diff --git a/src/cmd/asm/internal/lex/lex.go b/src/cmd/asm/internal/lex/lex.go
index c48b74a101..6fce55f7f4 100644
--- a/src/cmd/asm/internal/lex/lex.go
+++ b/src/cmd/asm/internal/lex/lex.go
@@ -83,6 +83,11 @@ func NewLexer(name string, ctxt *obj.Link) TokenReader {
return input
}
+// InitHist sets the line count to 1, for reproducible testing.
+func InitHist() {
+ histLine = 1
+}
+
// The other files in this directory each contain an implementation of TokenReader.
// A TokenReader is like a reader, but returns lex tokens of type Token. It also can tell you what