Large diffs are not rendered by default.

@@ -0,0 +1,203 @@
// 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.

// This file encapsulates some of the odd characteristics of the ARM
// instruction set, to minimize its interaction with the core of the
// assembler.

package arch

import (
"strings"

"cmd/internal/obj"
"cmd/internal/obj/arm"
)

var armLS = map[string]uint8{
"U": arm.C_UBIT,
"S": arm.C_SBIT,
"W": arm.C_WBIT,
"P": arm.C_PBIT,
"PW": arm.C_WBIT | arm.C_PBIT,
"WP": arm.C_WBIT | arm.C_PBIT,
}

var armSCOND = map[string]uint8{
"EQ": arm.C_SCOND_EQ,
"NE": arm.C_SCOND_NE,
"CS": arm.C_SCOND_HS,
"HS": arm.C_SCOND_HS,
"CC": arm.C_SCOND_LO,
"LO": arm.C_SCOND_LO,
"MI": arm.C_SCOND_MI,
"PL": arm.C_SCOND_PL,
"VS": arm.C_SCOND_VS,
"VC": arm.C_SCOND_VC,
"HI": arm.C_SCOND_HI,
"LS": arm.C_SCOND_LS,
"GE": arm.C_SCOND_GE,
"LT": arm.C_SCOND_LT,
"GT": arm.C_SCOND_GT,
"LE": arm.C_SCOND_LE,
"AL": arm.C_SCOND_NONE,
"U": arm.C_UBIT,
"S": arm.C_SBIT,
"W": arm.C_WBIT,
"P": arm.C_PBIT,
"PW": arm.C_WBIT | arm.C_PBIT,
"WP": arm.C_WBIT | arm.C_PBIT,
"F": arm.C_FBIT,
"IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT,
"IAW": arm.C_WBIT | arm.C_UBIT,
"DBW": arm.C_WBIT | arm.C_PBIT,
"DAW": arm.C_WBIT,
"IB": arm.C_PBIT | arm.C_UBIT,
"IA": arm.C_UBIT,
"DB": arm.C_PBIT,
"DA": 0,
}

var armJump = map[string]bool{
"B": true,
"BL": true,
"BEQ": true,
"BNE": true,
"BCS": true,
"BHS": true,
"BCC": true,
"BLO": true,
"BMI": true,
"BPL": true,
"BVS": true,
"BVC": true,
"BHI": true,
"BLS": true,
"BGE": true,
"BLT": true,
"BGT": true,
"BLE": true,
"CALL": true,
}

func jumpArm(word string) bool {
return armJump[word]
}

// IsARMCMP reports whether the op (as defined by an arm.A* constant) is
// one of the comparison instructions that require special handling.
func IsARMCMP(op int) bool {
switch op {
case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
return true
}
return false
}

// IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
// one of the STREX-like instructions that require special handling.
func IsARMSTREX(op int) bool {
switch op {
case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
return true
}
return false
}

// IsARMMRC reports whether the op (as defined by an arm.A* constant) is
// MRC or MCR
func IsARMMRC(op int) bool {
switch op {
case arm.AMRC /*, arm.AMCR*/ :
return true
}
return false
}

// IsARMMULA reports whether the op (as defined by an arm.A* constant) is
// MULA, MULAWT or MULAWB, the 4-operand instructions.
func IsARMMULA(op int) bool {
switch op {
case arm.AMULA, arm.AMULAWB, arm.AMULAWT:
return true
}
return false
}

var bcode = []int{
arm.ABEQ,
arm.ABNE,
arm.ABCS,
arm.ABCC,
arm.ABMI,
arm.ABPL,
arm.ABVS,
arm.ABVC,
arm.ABHI,
arm.ABLS,
arm.ABGE,
arm.ABLT,
arm.ABGT,
arm.ABLE,
arm.AB,
obj.ANOP,
}

// ARMConditionCodes handles the special condition code situation for the ARM.
// It returns a boolean to indicate success; failure means cond was unrecognized.
func ARMConditionCodes(prog *obj.Prog, cond string) bool {
if cond == "" {
return true
}
bits, ok := ParseARMCondition(cond)
if !ok {
return false
}
/* hack to make B.NE etc. work: turn it into the corresponding conditional */
if prog.As == arm.AB {
prog.As = int16(bcode[(bits^arm.C_SCOND_XOR)&0xf])
bits = (bits &^ 0xf) | arm.C_SCOND_NONE
}
prog.Scond = bits
return true
}

// ParseARMCondition parses the conditions attached to an ARM instruction.
// The input is a single string consisting of period-separated condition
// codes, such as ".P.W". An initial period is ignored.
func ParseARMCondition(cond string) (uint8, bool) {
if strings.HasPrefix(cond, ".") {
cond = cond[1:]
}
if cond == "" {
return arm.C_SCOND_NONE, true
}
names := strings.Split(cond, ".")
bits := uint8(0)
for _, name := range names {
if b, present := armLS[name]; present {
bits |= b
continue
}
if b, present := armSCOND[name]; present {
bits = (bits &^ arm.C_SCOND) | b
continue
}
return 0, false
}
return bits, true
}

func armRegisterNumber(name string, n int16) (int16, bool) {
if n < 0 || 15 < n {
return 0, false
}
switch name {
case "R":
return arm.REG_R0 + n, true
case "F":
return arm.REG_F0 + n, true
}
return 0, false
}
@@ -0,0 +1,87 @@
// 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.

// This file encapsulates some of the odd characteristics of the ARM
// instruction set, to minimize its interaction with the core of the
// assembler.

package arch

import "cmd/internal/obj/ppc64"

func jumpPPC64(word string) bool {
switch word {
case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "CALL":
return true
}
return false
}

// IsPPC64RLD reports whether the op (as defined by an ppc64.A* constant) is
// one of the RLD-like instructions that require special handling.
// The FMADD-like instructions behave similarly.
func IsPPC64RLD(op int) bool {
switch op {
case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC,
ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC,
ppc64.ARLWMI, ppc64.ARLWMICC, ppc64.ARLWNM, ppc64.ARLWNMCC:
return true
case ppc64.AFMADD, ppc64.AFMADDCC, ppc64.AFMADDS, ppc64.AFMADDSCC,
ppc64.AFMSUB, ppc64.AFMSUBCC, ppc64.AFMSUBS, ppc64.AFMSUBSCC,
ppc64.AFNMADD, ppc64.AFNMADDCC, ppc64.AFNMADDS, ppc64.AFNMADDSCC,
ppc64.AFNMSUB, ppc64.AFNMSUBCC, ppc64.AFNMSUBS, ppc64.AFNMSUBSCC:
return true
}
return false
}

// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is
// one of the CMP instructions that require special handling.
func IsPPC64CMP(op int) bool {
switch op {
case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU:
return true
}
return false
}

// IsPPC64NEG reports whether the op (as defined by an ppc64.A* constant) is
// one of the NEG-like instructions that require special handling.
func IsPPC64NEG(op int) bool {
switch op {
case ppc64.AADDMECC, ppc64.AADDMEVCC, ppc64.AADDMEV, ppc64.AADDME,
ppc64.AADDZECC, ppc64.AADDZEVCC, ppc64.AADDZEV, ppc64.AADDZE,
ppc64.ACNTLZDCC, ppc64.ACNTLZD, ppc64.ACNTLZWCC, ppc64.ACNTLZW,
ppc64.AEXTSBCC, ppc64.AEXTSB, ppc64.AEXTSHCC, ppc64.AEXTSH,
ppc64.AEXTSWCC, ppc64.AEXTSW, ppc64.ANEGCC, ppc64.ANEGVCC,
ppc64.ANEGV, ppc64.ANEG, ppc64.ASLBMFEE, ppc64.ASLBMFEV,
ppc64.ASLBMTE, ppc64.ASUBMECC, ppc64.ASUBMEVCC, ppc64.ASUBMEV,
ppc64.ASUBME, ppc64.ASUBZECC, ppc64.ASUBZEVCC, ppc64.ASUBZEV,
ppc64.ASUBZE:
return true
}
return false
}

func ppc64RegisterNumber(name string, n int16) (int16, bool) {
switch name {
case "CR":
if 0 <= n && n <= 7 {
return ppc64.REG_C0 + n, true
}
case "F":
if 0 <= n && n <= 31 {
return ppc64.REG_F0 + n, true
}
case "R":
if 0 <= n && n <= 31 {
return ppc64.REG_R0 + n, true
}
case "SPR":
if 0 <= n && n <= 1024 {
return ppc64.REG_SPR0 + n, true
}
}
return 0, false
}

Large diffs are not rendered by default.

@@ -0,0 +1,83 @@
// 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)
// For Windows.
result = strings.Replace(result, `testdata\`, `testdata/`, -1)
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")
}

func TestAMD64EndToEnd(t *testing.T) {
testEndToEnd(t, "amd64")
}
@@ -0,0 +1,73 @@
// +build ignore

// 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 (
"cmd/asm/internal/lex"
"testing"
"text/scanner"
)

type exprTest struct {
input string
output int64
atEOF bool
}

var exprTests = []exprTest{
// Simple
{"0", 0, true},
{"3", 3, true},
{"070", 8 * 7, true},
{"0x0f", 15, true},
{"0xFF", 255, true},
{"9223372036854775807", 9223372036854775807, true}, // max int64
// Unary
{"-0", 0, true},
{"~0", -1, true},
{"~0*0", 0, true},
{"+3", 3, true},
{"-3", -3, true},
{"-9223372036854775808", -9223372036854775808, true}, // min int64
// Binary
{"3+4", 3 + 4, true},
{"3-4", 3 - 4, true},
{"2|5", 2 | 5, true},
{"3^4", 3 ^ 4, true},
{"3*4", 3 * 4, true},
{"14/4", 14 / 4, true},
{"3<<4", 3 << 4, true},
{"48>>3", 48 >> 3, true},
{"3&9", 3 & 9, true},
// General
{"3*2+3", 3*2 + 3, true},
{"3+2*3", 3 + 2*3, true},
{"3*(2+3)", 3 * (2 + 3), true},
{"3*-(2+3)", 3 * -(2 + 3), true},
{"3<<2+4", 3<<2 + 4, true},
{"3<<2+4", 3<<2 + 4, true},
{"3<<(2+4)", 3 << (2 + 4), true},
// Junk at EOF.
{"3 x", 3, false},
}

func TestExpr(t *testing.T) {
p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
for i, test := range exprTests {
p.start(lex.Tokenize(test.input))
result := int64(p.expr())
if result != test.output {
t.Errorf("%d: %q evaluated to %d; expected %d", i, test.input, result, test.output)
}
tok := p.next()
if test.atEOF && tok.ScanToken != scanner.EOF {
t.Errorf("%d: %q: at EOF got %s", i, test.input, tok)
} else if !test.atEOF && tok.ScanToken == scanner.EOF {
t.Errorf("%d: %q: expected not EOF but at EOF", i, test.input)
}
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,56 @@
5 00001 (testdata/amd64.s:5) TEXT foo+0(SB),$0
8 00002 (testdata/amd64.s:8) NEGQ ,R11
9 00003 (testdata/amd64.s:9) NEGQ ,4(R11)
10 00004 (testdata/amd64.s:10) NEGQ ,foo+4(SB)
13 00005 (testdata/amd64.s:13) INT $4,
14 00006 (testdata/amd64.s:14) DIVB R11,
15 00007 (testdata/amd64.s:15) DIVB 4(R11),
16 00008 (testdata/amd64.s:16) DIVB foo+4(SB),
19 00009 (testdata/amd64.s:19) SUBQ $4,DI
20 00010 (testdata/amd64.s:20) SUBQ R11,DI
21 00011 (testdata/amd64.s:21) SUBQ 4(R11),DI
22 00012 (testdata/amd64.s:22) SUBQ foo+4(SB),DI
23 00013 (testdata/amd64.s:23) SUBQ $4,8(R12)
24 00014 (testdata/amd64.s:24) SUBQ R11,8(R12)
25 00015 (testdata/amd64.s:25) SUBQ R11,foo+4(SB)
28 00016 (testdata/amd64.s:28) CMPB CX,$4
32 00017 (testdata/amd64.s:32) JCS ,13(PC)
33 00018 (testdata/amd64.s:33) JCS ,17
36 00019 (testdata/amd64.s:36) JMP ,15(PC)
37 00020 (testdata/amd64.s:37) JMP ,17
38 00021 (testdata/amd64.s:38) JMP ,foo+4(SB)
39 00022 (testdata/amd64.s:39) JMP ,bar<>+4(SB)
40 00023 (testdata/amd64.s:40) JMP ,bar<>+4(SB)(R11*4)
41 00024 (testdata/amd64.s:41) JMP ,4(SP)
42 00025 (testdata/amd64.s:42) JMP ,(R12)
44 00026 (testdata/amd64.s:44) JMP ,(R12)(R13*4)
45 00027 (testdata/amd64.s:45) JMP ,(AX)
46 00028 (testdata/amd64.s:46) JMP ,(SP)
48 00029 (testdata/amd64.s:48) JMP ,(AX)(AX*4)
49 00030 (testdata/amd64.s:49) JMP ,4(SP)
50 00031 (testdata/amd64.s:50) JMP ,(R12)
52 00032 (testdata/amd64.s:52) JMP ,(R12)(R13*4)
53 00033 (testdata/amd64.s:53) JMP ,(AX)
54 00034 (testdata/amd64.s:54) JMP ,(SP)
56 00035 (testdata/amd64.s:56) JMP ,(AX)(AX*4)
57 00036 (testdata/amd64.s:57) JMP ,R13
60 00037 (testdata/amd64.s:60) NOP ,
61 00038 (testdata/amd64.s:61) NOP AX,
62 00039 (testdata/amd64.s:62) NOP foo+4(SB),
65 00040 (testdata/amd64.s:65) SHLL R11,R12
66 00041 (testdata/amd64.s:66) SHLL R11,foo+4(SB)
67 00042 (testdata/amd64.s:67) SHLL R11,R11:AX
70 00043 (testdata/amd64.s:70) MOVL AX,R11
71 00044 (testdata/amd64.s:71) MOVL $4,R11
72 00045 (testdata/amd64.s:72) MOVL AX,AX:CS
75 00046 (testdata/amd64.s:75) IMULB $4,
76 00047 (testdata/amd64.s:76) IMULB R11,
77 00048 (testdata/amd64.s:77) IMULB $4,R11
78 00049 (testdata/amd64.s:78) IMULB R11,R12
79 00050 (testdata/amd64.s:79) IMULB R11,foo+4(SB)
82 00051 (testdata/amd64.s:82) CMPPD R11,$4,R12
83 00052 (testdata/amd64.s:83) CMPPD R11,foo+4(SB)
86 00053 (testdata/amd64.s:86) PINSRW R11,$4,AX
87 00054 (testdata/amd64.s:87) PINSRW foo+4(SB),$4,AX
90 00055 (testdata/amd64.s:90) RETFL $4,
93 00056 (testdata/amd64.s:93) RET ,
@@ -0,0 +1,93 @@
// This input was created by taking the instruction productions in
// the old assembler's (6a's) grammar and hand-writing complete
// instructions for each rule, to guarantee we cover the same space.

TEXT foo(SB), 0, $0

// LTYPE1 nonrem { outcode($1, &$2); }
NEGQ R11
NEGQ 4(R11)
NEGQ foo+4(SB)

// LTYPE2 rimnon { outcode($1, &$2); }
INT $4
DIVB R11
DIVB 4(R11)
DIVB foo+4(SB)

// LTYPE3 rimrem { outcode($1, &$2); }
SUBQ $4, DI
SUBQ R11, DI
SUBQ 4(R11), DI
SUBQ foo+4(SB), DI
SUBQ $4, 8(R12)
SUBQ R11, 8(R12)
SUBQ R11, foo+4(SB)

// LTYPE4 remrim { outcode($1, &$2); }
CMPB CX, $4

// LTYPER nonrel { outcode($1, &$2); }
label:
JB -4(PC)
JB label

// LTYPEC spec3 { outcode($1, &$2); }
JMP -4(PC)
JMP label
JMP foo+4(SB)
JMP bar<>+4(SB)
JMP bar<>+4(SB)(R11*4)
JMP *4(SP)
JMP *(R12)
JMP *(R12*4)
JMP *(R12)(R13*4)
JMP *(AX)
JMP *(SP)
JMP *(AX*4)
JMP *(AX)(AX*4)
JMP 4(SP)
JMP (R12)
JMP (R12*4)
JMP (R12)(R13*4)
JMP (AX)
JMP (SP)
JMP (AX*4)
JMP (AX)(AX*4)
JMP R13

// LTYPEN spec4 { outcode($1, &$2); }
NOP
NOP AX
NOP foo+4(SB)

// LTYPES spec5 { outcode($1, &$2); }
SHLL R11, R12
SHLL R11, foo+4(SB)
SHLL R11, R11:AX

// LTYPEM spec6 { outcode($1, &$2); }
MOVL AX, R11
MOVL $4, R11
MOVL AX, AX:CS

// LTYPEI spec7 { outcode($1, &$2); }
IMULB $4
IMULB R11
IMULB $4, R11
IMULB R11, R12
IMULB R11, foo+4(SB)

// LTYPEXC spec8 { outcode($1, &$2); }
CMPPD R11, R12, 4
CMPPD R11, foo+4(SB), 4

// LTYPEX spec9 { outcode($1, &$2); }
PINSRW $4, R11, AX
PINSRW $4, foo+4(SB), AX

// LTYPERT spec10 { outcode($1, &$2); }
RETFL $4

// LTYPE0 nonnon { outcode($1, &$2); }
RET
@@ -0,0 +1,53 @@
5 00001 (testdata/arm.s:5) TEXT foo+0(SB),0,$0
14 00002 (testdata/arm.s:14) ADD $1,R2,R3
15 00003 (testdata/arm.s:15) ADD R1<<R2,R3,R4
16 00004 (testdata/arm.s:16) ADD R1>>R2,R3,R4
17 00005 (testdata/arm.s:17) ADD R1@>R2,R3,R4
18 00006 (testdata/arm.s:18) ADD R1->R2,R3,R4
19 00007 (testdata/arm.s:19) ADD R1,R2,R3
20 00008 (testdata/arm.s:20) ADD R1<<R2,R3,R4
30 00009 (testdata/arm.s:30) ADD $1,R2
31 00010 (testdata/arm.s:31) ADD R1<<R2,R3
32 00011 (testdata/arm.s:32) ADD R1>>R2,R3
33 00012 (testdata/arm.s:33) ADD R1@>R2,R3
34 00013 (testdata/arm.s:34) ADD R1->R2,R3
35 00014 (testdata/arm.s:35) ADD R1,R2
44 00015 (testdata/arm.s:44) CLZ.S R1,R2
53 00016 (testdata/arm.s:53) MOVW.S R1,R2
54 00017 (testdata/arm.s:54) MOVW.S $1,R2
55 00018 (testdata/arm.s:55) MOVW.S R1<<R2,R3
64 00019 (testdata/arm.s:64) JMP.S ,20(PC)
70 00020 (testdata/arm.s:70) JMP.S ,0(R2)
71 00021 (testdata/arm.s:71) JMP.S ,foo+0(SB)
72 00022 (testdata/arm.s:72) JMP.S ,bar<>+0(SB)
81 00023 (testdata/arm.s:81) BX 0(R2),
90 00024 (testdata/arm.s:90) BEQ ,25(PC)
99 00025 (testdata/arm.s:99) SWI.S ,R1
100 00026 (testdata/arm.s:100) SWI.S ,0(R1)
101 00027 (testdata/arm.s:101) SWI.S ,foo+0(SB)
110 00028 (testdata/arm.s:110) CMP.S $1,R2,
111 00029 (testdata/arm.s:111) CMP.S R1<<R2,R3,
112 00030 (testdata/arm.s:112) CMP.S R1,R2,
126 00031 (testdata/arm.s:126) MOVM 0(R1),[R2,R5,R8,R10]
127 00032 (testdata/arm.s:127) MOVM 0(R1),[R2,R3,R4,R5]
128 00033 (testdata/arm.s:128) MOVM.S 0(R1),[R2]
139 00034 (testdata/arm.s:139) MOVM [R2,R5,R8,R10],0(R1)
140 00035 (testdata/arm.s:140) MOVM [R2,R3,R4,R5],0(R1)
141 00036 (testdata/arm.s:141) MOVM.S [R2],0(R1)
150 00037 (testdata/arm.s:150) STREX.S 0(R2),R1,R3
156 00038 (testdata/arm.s:156) STREX.S 0(R2),R1,R1
162 00039 (testdata/arm.s:162) STREX.S 0(R2),R3,R3
170 00040 (testdata/arm.s:170) CASE.S R1,
179 00041 (testdata/arm.s:179) WORD ,$1234
188 00042 (testdata/arm.s:188) ABSF.S F1,F2
194 00043 (testdata/arm.s:194) ADDD.S F1,F2
195 00044 (testdata/arm.s:195) ADDD.S $0.5,F2
201 00045 (testdata/arm.s:201) ADDD.S F1,F2,F3
202 00046 (testdata/arm.s:202) ADDD.S $0.5,F2,F3
208 00047 (testdata/arm.s:208) CMPD.S F1,F2
242 00048 (testdata/arm.s:242) MULL R1,R2,(R3, R4)
254 00049 (testdata/arm.s:254) MULAWT R1,R2,R3, R4
262 00050 (testdata/arm.s:262) PLD 0(R1),
263 00051 (testdata/arm.s:263) PLD 4(R1),
272 00052 (testdata/arm.s:272) RET ,
281 00053 (testdata/arm.s:281) END ,
@@ -0,0 +1,281 @@
// This input was created by taking the instruction productions in
// the old assembler's (5a's) grammar and hand-writing complete
// instructions for each rule, to guarantee we cover the same space.

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);
// }
// TODO: Disabled until printout for this instruction is the same for 32 and 64 bits.
// 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
@@ -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 ,

Large diffs are not rendered by default.

@@ -0,0 +1,67 @@
// 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 flags implements top-level flags and the usage message for the assembler.
package flags

import (
"flag"
"fmt"
"os"
"path/filepath"
"strings"
)

var (
Debug = flag.Bool("debug", false, "dump instructions as they are parsed")
OutputFile = flag.String("o", "", "output file; default foo.6 for /a/b/c/foo.s on amd64")
PrintOut = flag.Bool("S", false, "print assembly and machine code")
TrimPath = flag.String("trimpath", "", "remove prefix from recorded source file paths (unused TODO)")
)

var (
D MultiFlag
I MultiFlag
)

func init() {
flag.Var(&D, "D", "predefined symbol with optional simple value -D=identifer=value; can be set multiple times")
flag.Var(&I, "I", "include directory; can be set multiple times")
}

// MultiFlag allows setting a value multiple times to collect a list, as in -I=dir1 -I=dir2.
type MultiFlag []string

func (m *MultiFlag) String() string {
return fmt.Sprint(*m)
}

func (m *MultiFlag) Set(val string) error {
(*m) = append(*m, val)
return nil
}

func Usage() {
fmt.Fprintf(os.Stderr, "usage: asm [options] file.s\n")
fmt.Fprintf(os.Stderr, "Flags:\n")
flag.PrintDefaults()
os.Exit(2)
}

func Parse(theChar int) {
flag.Usage = Usage
flag.Parse()
if flag.NArg() != 1 {
flag.Usage()
}

// Flag refinement.
if *OutputFile == "" {
input := filepath.Base(flag.Arg(0))
if strings.HasSuffix(input, ".s") {
input = input[:len(input)-2]
}
*OutputFile = fmt.Sprintf("%s.%c", input, theChar)
}
}

Large diffs are not rendered by default.

@@ -0,0 +1,157 @@
// 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 lex implements lexical analysis for the assembler.
package lex

import (
"fmt"
"log"
"os"
"strings"
"text/scanner"

"cmd/internal/obj"
)

// A ScanToken represents an input item. It is a simple wrapping of rune, as
// returned by text/scanner.Scanner, plus a couple of extra values.
type ScanToken rune

const (
// Asm defines some two-character lexemes. We make up
// a rune/ScanToken value for them - ugly but simple.
LSH ScanToken = -1000 - iota // << Left shift.
RSH // >> Logical right shift.
ARR // -> Used on ARM for shift type 3, arithmetic right shift.
ROT // @> Used on ARM for shift type 4, rotate right.
macroName // name of macro that should not be expanded
)

// IsRegisterShift reports whether the token is one of the ARM register shift operators.
func IsRegisterShift(r ScanToken) bool {
return ROT <= r && r <= LSH // Order looks backwards because these are negative.
}

func (t ScanToken) String() string {
switch t {
case scanner.EOF:
return "EOF"
case scanner.Ident:
return "identifier"
case scanner.Int:
return "integer constant"
case scanner.Float:
return "float constant"
case scanner.Char:
return "rune constant"
case scanner.String:
return "string constant"
case scanner.RawString:
return "raw string constant"
case scanner.Comment:
return "comment"
default:
return fmt.Sprintf("%q", rune(t))
}
}

var (
// It might be nice if these weren't global.
linkCtxt *obj.Link // The link context for all instructions.
histLine int = 1 // The cumulative count of lines processed.
)

// HistLine reports the cumulative source line number of the token,
// for use in the Prog structure for the linker. (It's always handling the
// instruction from the current lex line.)
// It returns int32 because that's what type ../asm prefers.
func HistLine() int32 {
return int32(histLine)
}

// NewLexer returns a lexer for the named file and the given link context.
func NewLexer(name string, ctxt *obj.Link) TokenReader {
linkCtxt = ctxt
input := NewInput(name)
fd, err := os.Open(name)
if err != nil {
log.Fatalf("asm: %s\n", err)
}
input.Push(NewTokenizer(name, fd, fd))
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
// the text of the most recently returned token is, and where it was found.
// The underlying scanner elides all spaces except newline, so the input looks like a stream of
// Tokens; original spacing is lost but we don't need it.
type TokenReader interface {
// Next returns the next token.
Next() ScanToken
// The following methods all refer to the most recent token returned by Next.
// Text returns the original string representation of the token.
Text() string
// File reports the source file name of the token.
File() string
// Line reports the source line number of the token.
Line() int
// Col reports the source column number of the token.
Col() int
// SetPos sets the file and line number.
SetPos(line int, file string)
// Close does any teardown required.
Close()
}

// A Token is a scan token plus its string value.
// A macro is stored as a sequence of Tokens with spaces stripped.
type Token struct {
ScanToken
text string
}

// Make returns a Token with the given rune (ScanToken) and text representation.
func Make(token ScanToken, text string) Token {
// If the symbol starts with center dot, as in ·x, rewrite it as ""·x
if token == scanner.Ident && strings.HasPrefix(text, "\u00B7") {
text = `""` + text
}
// Substitute the substitutes for . and /.
text = strings.Replace(text, "\u00B7", ".", -1)
text = strings.Replace(text, "\u2215", "/", -1)
return Token{ScanToken: token, text: text}
}

func (l Token) String() string {
return l.text
}

// A Macro represents the definition of a #defined macro.
type Macro struct {
name string // The #define name.
args []string // Formal arguments.
tokens []Token // Body of macro.
}

// Tokenize turns a string into a list of Tokens; used to parse the -D flag and in tests.
func Tokenize(str string) []Token {
t := NewTokenizer("command line", strings.NewReader(str), nil)
var tokens []Token
for {
tok := t.Next()
if tok == scanner.EOF {
break
}
tokens = append(tokens, Make(tok, t.Text()))
}
return tokens
}
@@ -0,0 +1,154 @@
// 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 lex

import (
"bytes"
"strings"
"testing"
"text/scanner"
)

type lexTest struct {
name string
input string
output string
}

var lexTests = []lexTest{
{
"empty",
"",
"",
},
{
"simple",
"1 (a)",
"1.(.a.)",
},
{
"simple define",
lines(
"#define A 1234",
"A",
),
"1234.\n",
},
{
"define without value",
"#define A",
"",
},
{
"macro without arguments",
"#define A() 1234\n" + "A()\n",
"1234.\n",
},
{
"macro with just parens as body",
"#define A () \n" + "A\n",
"(.).\n",
},
{
"macro with parens but no arguments",
"#define A (x) \n" + "A\n",
"(.x.).\n",
},
{
"macro with arguments",
"#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n",
"1.+.3.+.2.\n",
},
{
"argumented macro invoked without arguments",
lines(
"#define X() foo ",
"X()",
"X",
),
"foo.\n.X.\n",
},
{
"multiline macro without arguments",
lines(
"#define A 1\\",
"\t2\\",
"\t3",
"before",
"A",
"after",
),
"before.\n.1.\n.2.\n.3.\n.after.\n",
},
{
"multiline macro with arguments",
lines(
"#define A(a, b, c) a\\",
"\tb\\",
"\tc",
"before",
"A(1, 2, 3)",
"after",
),
"before.\n.1.\n.2.\n.3.\n.after.\n",
},
{
"LOAD macro",
lines(
"#define LOAD(off, reg) \\",
"\tMOVBLZX (off*4)(R12), reg \\",
"\tADDB reg, DX",
"",
"LOAD(8, AX)",
),
"\n.\n.MOVBLZX.(.8.*.4.).(.R12.).,.AX.\n.ADDB.AX.,.DX.\n",
},
{
"nested multiline macro",
lines(
"#define KEYROUND(xmm, load, off, r1, r2, index) \\",
"\tMOVBLZX (BP)(DX*4), R8 \\",
"\tload((off+1), r2) \\",
"\tMOVB R8, (off*4)(R12) \\",
"\tPINSRW $index, (BP)(R8*4), xmm",
"#define LOAD(off, reg) \\",
"\tMOVBLZX (off*4)(R12), reg \\",
"\tADDB reg, DX",
"KEYROUND(X0, LOAD, 8, AX, BX, 0)",
),
"\n.MOVBLZX.(.BP.).(.DX.*.4.).,.R8.\n.\n.MOVBLZX.(.(.8.+.1.).*.4.).(.R12.).,.BX.\n.ADDB.BX.,.DX.\n.MOVB.R8.,.(.8.*.4.).(.R12.).\n.PINSRW.$.0.,.(.BP.).(.R8.*.4.).,.X0.\n",
},
}

func TestLex(t *testing.T) {
for _, test := range lexTests {
input := NewInput(test.name)
input.Push(NewTokenizer(test.name, strings.NewReader(test.input), nil))
result := drain(input)
if result != test.output {
t.Errorf("%s: got %q expected %q", test.name, result, test.output)
}
}
}

// lines joins the arguments together as complete lines.
func lines(a ...string) string {
return strings.Join(a, "\n") + "\n"
}

// drain returns a single string representing the processed input tokens.
func drain(input *Input) string {
var buf bytes.Buffer
for {
tok := input.Next()
if tok == scanner.EOF {
return buf.String()
}
if buf.Len() > 0 {
buf.WriteByte('.')
}
buf.WriteString(input.Text())
}
}
@@ -0,0 +1,59 @@
// 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 lex

import "text/scanner"

// A Slice reads from a slice of Tokens.
type Slice struct {
tokens []Token
fileName string
line int
pos int
}

func NewSlice(fileName string, line int, tokens []Token) *Slice {
return &Slice{
tokens: tokens,
fileName: fileName,
line: line,
pos: -1, // Next will advance to zero.
}
}

func (s *Slice) Next() ScanToken {
s.pos++
if s.pos >= len(s.tokens) {
return scanner.EOF
}
return s.tokens[s.pos].ScanToken
}

func (s *Slice) Text() string {
return s.tokens[s.pos].text
}

func (s *Slice) File() string {
return s.fileName
}

func (s *Slice) Line() int {
return s.line
}

func (s *Slice) Col() int {
// Col is only called when defining a macro, which can't reach here.
panic("cannot happen: slice col")
}

func (s *Slice) SetPos(line int, file string) {
// Cannot happen because we only have slices of already-scanned
// text, but be prepared.
s.line = line
s.fileName = file
}

func (s *Slice) Close() {
}
@@ -0,0 +1,53 @@
// 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 lex

import "text/scanner"

// A Stack is a stack of TokenReaders. As the top TokenReader hits EOF,
// it resumes reading the next one down.
type Stack struct {
tr []TokenReader
}

// Push adds tr to the top (end) of the input stack. (Popping happens automatically.)
func (s *Stack) Push(tr TokenReader) {
s.tr = append(s.tr, tr)
}

func (s *Stack) Next() ScanToken {
tos := s.tr[len(s.tr)-1]
tok := tos.Next()
for tok == scanner.EOF && len(s.tr) > 1 {
tos.Close()
// Pop the topmost item from the stack and resume with the next one down.
s.tr = s.tr[:len(s.tr)-1]
tok = s.Next()
}
return tok
}

func (s *Stack) Text() string {
return s.tr[len(s.tr)-1].Text()
}

func (s *Stack) File() string {
return s.tr[len(s.tr)-1].File()
}

func (s *Stack) Line() int {
return s.tr[len(s.tr)-1].Line()
}

func (s *Stack) Col() int {
return s.tr[len(s.tr)-1].Col()
}

func (s *Stack) SetPos(line int, file string) {
s.tr[len(s.tr)-1].SetPos(line, file)
}

func (s *Stack) Close() { // Unused.
}
@@ -0,0 +1,154 @@
// 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 lex

import (
"io"
"os"
"strings"
"text/scanner"
"unicode"

"cmd/internal/obj"
)

// A Tokenizer is a simple wrapping of text/scanner.Scanner, configured
// for our purposes and made a TokenReader. It forms the lowest level,
// turning text from readers into tokens.
type Tokenizer struct {
tok ScanToken
s *scanner.Scanner
line int
fileName string
file *os.File // If non-nil, file descriptor to close.
}

func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
var s scanner.Scanner
s.Init(r)
// Newline is like a semicolon; other space characters are fine.
s.Whitespace = 1<<'\t' | 1<<'\r' | 1<<' '
// Don't skip comments: we need to count newlines.
s.Mode = scanner.ScanChars |
scanner.ScanFloats |
scanner.ScanIdents |
scanner.ScanInts |
scanner.ScanStrings |
scanner.ScanComments
s.Position.Filename = name
s.IsIdentRune = isIdentRune
if file != nil {
obj.Linklinehist(linkCtxt, histLine, name, 0)
}
return &Tokenizer{
s: &s,
line: 1,
fileName: name,
file: file,
}
}

// We want center dot (·) and division slash (∕) to work as identifier characters.
func isIdentRune(ch rune, i int) bool {
if unicode.IsLetter(ch) {
return true
}
switch ch {
case '_': // Underscore; traditional.
return true
case '\u00B7': // Represents the period in runtime.exit. U+00B7 '·' middle dot
return true
case '\u2215': // Represents the slash in runtime/debug.setGCPercent. U+2215 '∕' division slash
return true
}
// Digits are OK only after the first character.
return i > 0 && unicode.IsDigit(ch)
}

func (t *Tokenizer) Text() string {
switch t.tok {
case LSH:
return "<<"
case RSH:
return ">>"
case ARR:
return "->"
case ROT:
return "@>"
}
return t.s.TokenText()
}

func (t *Tokenizer) File() string {
return t.fileName
}

func (t *Tokenizer) Line() int {
return t.line
}

func (t *Tokenizer) Col() int {
return t.s.Pos().Column
}

func (t *Tokenizer) SetPos(line int, file string) {
t.line = line
t.fileName = file
}

func (t *Tokenizer) Next() ScanToken {
s := t.s
for {
t.tok = ScanToken(s.Scan())
if t.tok != scanner.Comment {
break
}
length := strings.Count(s.TokenText(), "\n")
t.line += length
histLine += length
// TODO: If we ever have //go: comments in assembly, will need to keep them here.
// For now, just discard all comments.
}
switch t.tok {
case '\n':
if t.file != nil {
histLine++
}
t.line++
case '-':
if s.Peek() == '>' {
s.Next()
t.tok = ARR
return ARR
}
case '@':
if s.Peek() == '>' {
s.Next()
t.tok = ROT
return ROT
}
case '<':
if s.Peek() == '<' {
s.Next()
t.tok = LSH
return LSH
}
case '>':
if s.Peek() == '>' {
s.Next()
t.tok = RSH
return RSH
}
}
return t.tok
}

func (t *Tokenizer) Close() {
if t.file != nil {
t.file.Close()
// It's an open file, so pop the line history.
obj.Linklinehist(linkCtxt, histLine, "<pop>", 0)
}
}
@@ -0,0 +1,61 @@
// Copyright 2014 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 main

import (
"flag"
"fmt"
"log"
"os"

"cmd/asm/internal/arch"
"cmd/asm/internal/asm"
"cmd/asm/internal/flags"
"cmd/asm/internal/lex"

"cmd/internal/obj"
)

func main() {
log.SetFlags(0)
log.SetPrefix("asm: ")

GOARCH := obj.Getgoarch()

architecture := arch.Set(GOARCH)
if architecture == nil {
log.Fatalf("asm: unrecognized architecture %s", GOARCH)
}

flags.Parse(architecture.Thechar)

// Create object file, write header.
fd, err := os.Create(*flags.OutputFile)
if err != nil {
log.Fatal(err)
}
ctxt := obj.Linknew(architecture.LinkArch)
if *flags.PrintOut {
ctxt.Debugasm = 1
}
ctxt.Bso = obj.Binitw(os.Stdout)
defer obj.Bflush(ctxt.Bso)
ctxt.Diag = log.Fatalf
output := obj.Binitw(fd)
fmt.Fprintf(output, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
fmt.Fprintf(output, "!\n")

lexer := lex.NewLexer(flag.Arg(0), ctxt)
parser := asm.NewParser(ctxt, architecture, lexer)
pList := obj.Linknewplist(ctxt)
var ok bool
pList.Firstpc, ok = parser.Parse()
if !ok {
log.Fatalf("asm: assembly of %s failed", flag.Arg(0))
os.Exit(1)
}
obj.Writeobjdirect(ctxt, output)
obj.Bflush(output)
}
@@ -572,6 +572,8 @@ getc(void)
c = peekc;
if(c != IGN) {
peekc = IGN;
if(c == '\n')
lineno++;
return c;
}
c = GETC();
@@ -633,7 +635,7 @@ loop:
return l;
}
}
peekc = c;
unget(c);
return l;
}
switch(c)
@@ -36,6 +36,7 @@ var (
oldgoarch string
oldgochar string
slash string
exe string
defaultcc string
defaultcflags string
defaultldflags string
@@ -374,6 +375,7 @@ var oldtool = []string{
// not be in release branches.
var unreleased = []string{
"src/cmd/link",
"src/cmd/objwriter",
"src/debug/goobj",
"src/old",
}
@@ -534,21 +536,6 @@ var deptab = []struct {
"anames8.c",
"anames9.c",
}},
{"cmd/gc", []string{
"opnames.h",
}},
{"cmd/5g", []string{
"$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
}},
{"cmd/6g", []string{
"$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
}},
{"cmd/8g", []string{
"$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
}},
{"cmd/9g", []string{
"$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
}},
{"cmd/5l", []string{
"$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
}},
@@ -587,7 +574,6 @@ var gentab = []struct {
nameprefix string
gen func(string, string)
}{
{"opnames.h", gcopnames},
{"anames5.c", mkanames},
{"anames6.c", mkanames},
{"anames8.c", mkanames},
@@ -645,13 +631,20 @@ func install(dir string) {
ldargs = splitfields(defaultldflags)
}

islib := strings.HasPrefix(dir, "lib") || dir == "cmd/gc" || dir == "cmd/ld"
ispkg := !islib && !strings.HasPrefix(dir, "cmd/")
isgo := ispkg || dir == "cmd/go" || dir == "cmd/cgo"
isgo := true
ispkg := !strings.HasPrefix(dir, "cmd/") || strings.HasPrefix(dir, "cmd/internal/") || strings.HasPrefix(dir, "cmd/asm/internal/")
islib := false

exe := ""
if gohostos == "windows" {
exe = ".exe"
// Legacy C exceptions.
switch dir {
case "lib9", "libbio", "liblink", "cmd/gc", "cmd/ld":
islib = true
isgo = false
case "cmd/5l",
"cmd/6l",
"cmd/8l",
"cmd/9l":
isgo = false
}

// Start final link command line.
@@ -921,6 +914,8 @@ func install(dir string) {
compile = append(compile,
"-D", fmt.Sprintf("GOOS=%q", goos),
"-D", fmt.Sprintf("GOARCH=%q", goarch),
"-D", fmt.Sprintf("GOHOSTOS=%q", gohostos),
"-D", fmt.Sprintf("GOHOSTARCH=%q", gohostarch),
"-D", fmt.Sprintf("GOROOT=%q", goroot_final),
"-D", fmt.Sprintf("GOVERSION=%q", findgoversion()),
"-D", fmt.Sprintf("GOARM=%q", goarm),
@@ -1116,21 +1111,17 @@ func dopack(dst, src string, extra []string) {
}

// buildorder records the order of builds for the 'go bootstrap' command.
// The Go packages and commands must be in dependency order,
// maintained by hand, but the order doesn't change often.
var buildorder = []string{
// Legacy C programs.
"lib9",
"libbio",
"liblink",

"cmd/gc", // must be before g
"cmd/ld", // must be before l
"cmd/%sl", // must be before a, g
"cmd/%sa",
"cmd/%sg",

// The dependency order here was copied from a buildscript
// back when there were build scripts. Will have to
// be maintained by hand, but shouldn't change very
// often.
// Go libraries and programs for bootstrap.
"runtime",
"errors",
"sync/atomic",
@@ -1153,6 +1144,7 @@ var buildorder = []string{
"reflect",
"fmt",
"encoding",
"encoding/binary",
"encoding/json",
"flag",
"path/filepath",
@@ -1192,7 +1184,6 @@ var cleantab = []string{
"cmd/9a",
"cmd/9g",
"cmd/9l",
"cmd/gc",
"cmd/go",
"lib9",
"libbio",
@@ -1367,6 +1358,8 @@ func cmdbootstrap() {

setup()

bootstrapBuildTools()

// For the main bootstrap, building for host os/arch.
oldgoos = goos
oldgoarch = goarch
@@ -1379,6 +1372,31 @@ func cmdbootstrap() {
os.Setenv("GOARCH", goarch)
os.Setenv("GOOS", goos)

// TODO(rsc): Enable when appropriate.
// This step is only needed if we believe that the Go compiler built from Go 1.4
// will produce different object files than the Go compiler built from itself.
// In the absence of bugs, that should not happen.
// And if there are bugs, they're more likely in the current development tree
// than in a standard release like Go 1.4, so don't do this rebuild by default.
if false {
xprintf("##### Building Go toolchain using itself.\n")
for _, pattern := range buildorder {
if pattern == "cmd/go" {
break
}
dir := pattern
if strings.Contains(pattern, "%s") {
dir = fmt.Sprintf(pattern, gohostchar)
}
install(dir)
if oldgochar != gohostchar && strings.Contains(pattern, "%s") {
install(fmt.Sprintf(pattern, oldgochar))
}
}
xprintf("\n")
}

xprintf("##### Building compilers and go_bootstrap for host, %s/%s.\n", gohostos, gohostarch)
for _, pattern := range buildorder {
dir := pattern
if strings.Contains(pattern, "%s") {
@@ -32,3 +32,33 @@ func mkzversion(dir, file string) {

writefile(out, file, 0)
}

// mkzbootstrap writes cmd/internal/obj/zbootstrap.go:
//
// package obj
//
// const defaultGOROOT = <goroot>
// const defaultGO386 = <go386>
// const defaultGOARM = <goarm>
// const defaultGOOS = <goos>
// const defaultGOARCH = <goarch>
// const version = <version>
// const goexperiment = <goexperiment>
//
func mkzbootstrap(file string) {
out := fmt.Sprintf(
"// auto generated by go tool dist\n"+
"\n"+
"package obj\n"+
"\n"+
"const defaultGOROOT = `%s`\n"+
"const defaultGO386 = `%s`\n"+
"const defaultGOARM = `%s`\n"+
"const defaultGOOS = `%s`\n"+
"const defaultGOARCH = `%s`\n"+
"const version = `%s`\n"+
"const goexperiment = `%s`\n",
goroot_final, go386, goarm, gohostos, gohostarch, findgoversion(), os.Getenv("GOEXPERIMENT"))

writefile(out, file, 0)
}
@@ -0,0 +1,138 @@
// 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.

// Build toolchain using Go 1.4.
//
// The general strategy is to copy the source files we need into
// a new GOPATH workspace, adjust import paths appropriately,
// invoke the Go 1.4 go command to build those sources,
// and then copy the binaries back.

package main

import (
"os"
"strings"
)

// bootstrapDirs is a list of directories holding code that must be
// compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
// All directories in this list are relative to and must be below $GOROOT/src/cmd.
// The list is assumed to have two kinds of entries: names without slashes,
// which are commands, and entries beginning with internal/, which are
// packages supporting the commands.
var bootstrapDirs = []string{
"5a",
"5g",
"6a",
"6g",
"8a",
"8g",
"9a",
"9g",
"asm",
"asm/internal/arch",
"asm/internal/asm",
"asm/internal/flags",
"asm/internal/lex",
"internal/asm",
"internal/gc",
"internal/obj",
"internal/obj/arm",
"internal/obj/i386",
"internal/obj/ppc64",
"internal/obj/x86",
}

func bootstrapBuildTools() {
goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
if goroot_bootstrap == "" {
goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME"))
}
xprintf("##### Building Go toolchain using %s.\n", goroot_bootstrap)

mkzbootstrap(pathf("%s/src/cmd/internal/obj/zbootstrap.go", goroot))

// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
// We use a subdirectory of $GOROOT/pkg because that's the
// space within $GOROOT where we store all generated objects.
// We could use a temporary directory outside $GOROOT instead,
// but it is easier to debug on failure if the files are in a known location.
workspace := pathf("%s/pkg/bootstrap", goroot)
xremoveall(workspace)
base := pathf("%s/src/bootstrap", workspace)
xmkdirall(base)

// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
for _, dir := range bootstrapDirs {
src := pathf("%s/src/cmd/%s", goroot, dir)
dst := pathf("%s/%s", base, dir)
xmkdirall(dst)
for _, name := range xreaddirfiles(src) {
srcFile := pathf("%s/%s", src, name)
text := readfile(srcFile)
text = bootstrapFixImports(text, srcFile)
writefile(text, pathf("%s/%s", dst, name), 0)
}
}

// Set up environment for invoking Go 1.4 go command.
// GOROOT points at Go 1.4 GOROOT,
// GOPATH points at our bootstrap workspace,
// GOBIN is empty, so that binaries are installed to GOPATH/bin,
// and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
// so that Go 1.4 builds whatever kind of binary it knows how to build.
// Restore GOROOT, GOPATH, and GOBIN when done.
// Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
// because setup will take care of those when bootstrapBuildTools returns.

defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
os.Setenv("GOROOT", goroot_bootstrap)

defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
os.Setenv("GOPATH", workspace)

defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
os.Setenv("GOBIN", "")

os.Setenv("GOOS", "")
os.Setenv("GOHOSTOS", "")
os.Setenv("GOARCH", "")
os.Setenv("GOHOSTARCH", "")

// Run Go 1.4 to build binaries.
run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-v", "bootstrap/...")

// Copy binaries into tool binary directory.
for _, name := range bootstrapDirs {
if !strings.Contains(name, "/") {
copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), 1)
}
}

xprintf("\n")
}

func bootstrapFixImports(text, srcFile string) string {
lines := strings.SplitAfter(text, "\n")
inBlock := false
for i, line := range lines {
if strings.HasPrefix(line, "import (") {
inBlock = true
continue
}
if inBlock && strings.HasPrefix(line, ")") {
inBlock = false
continue
}
if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
lines[i] = strings.Replace(line, `"cmd/`, `"bootstrap/`, -1)
}
}

lines[0] = "// Do not edit. Bootstrap copy of " + srcFile + "\n\n" + lines[0]

return strings.Join(lines, "")
}
@@ -84,8 +84,23 @@ func run(dir string, mode int, cmd ...string) string {

xcmd := exec.Command(cmd[0], cmd[1:]...)
xcmd.Dir = dir
var data []byte
var err error
data, err := xcmd.CombinedOutput()

// If we want to show command output and this is not
// a background command, assume it's the only thing
// running, so we can just let it write directly stdout/stderr
// as it runs without fear of mixing the output with some
// other command's output. Not buffering lets the output
// appear as it is printed instead of once the command exits.
// This is most important for the invocation of 'go1.4 build -v bootstrap/...'.
if mode&(Background|ShowOutput) == ShowOutput {
xcmd.Stdout = os.Stdout
xcmd.Stderr = os.Stderr
err = xcmd.Run()
} else {
data, err = xcmd.CombinedOutput()
}
if err != nil && mode&CheckExit != 0 {
outputLock.Lock()
if len(data) > 0 {
@@ -275,7 +290,7 @@ func xremoveall(p string) {
os.RemoveAll(p)
}

// xreaddir replaces dst with a list of the names of the files in dir.
// xreaddir replaces dst with a list of the names of the files and subdirectories in dir.
// The names are relative to dir; they are not full paths.
func xreaddir(dir string) []string {
f, err := os.Open(dir)
@@ -290,6 +305,27 @@ func xreaddir(dir string) []string {
return names
}

// xreaddir replaces dst with a list of the names of the files in dir.
// The names are relative to dir; they are not full paths.
func xreaddirfiles(dir string) []string {
f, err := os.Open(dir)
if err != nil {
fatal("%v", err)
}
defer f.Close()
infos, err := f.Readdir(-1)
if err != nil {
fatal("reading %s: %v", dir, err)
}
var names []string
for _, fi := range infos {
if !fi.IsDir() {
names = append(names, fi.Name())
}
}
return names
}

// xworkdir creates a new temporary directory to hold object files
// and returns the name of that directory.
func xworkdir() string {
@@ -370,6 +406,8 @@ func main() {
if gohostarch == "" {
fatal("$objtype is unset")
}
case "windows":
exe = ".exe"
}

sysinit()

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.