| @@ -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 | ||
| } |
| @@ -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) | ||
| } | ||
| } | ||
| } |
| @@ -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 , |
| @@ -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) | ||
| } | ||
| } |
| @@ -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) | ||
| } |
| @@ -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, "") | ||
| } |