import (
"cmd/internal/obj"
"cmd/internal/obj/arm"
+ "cmd/internal/obj/arm64"
"cmd/internal/obj/ppc64"
"cmd/internal/obj/x86"
"fmt"
return archX86(&x86.Linkamd64p32)
case "arm":
return archArm()
+ case "arm64":
+ return archArm64()
case "ppc64":
a := archPPC64()
a.LinkArch = &ppc64.Linkppc64
}
}
+func archArm64() *Arch {
+ register := make(map[string]int16)
+ // Create maps for easy lookup of instruction names etc.
+ // Note that there is no list of names as there is for 386 and amd64.
+ register[arm64.Rconv(arm64.REGSP)] = int16(arm64.REGSP)
+ for i := arm64.REG_R0; i <= arm64.REG_R31; i++ {
+ register[arm64.Rconv(i)] = int16(i)
+ }
+ for i := arm64.REG_F0; i <= arm64.REG_F31; i++ {
+ register[arm64.Rconv(i)] = int16(i)
+ }
+ for i := arm64.REG_V0; i <= arm64.REG_V31; i++ {
+ register[arm64.Rconv(i)] = int16(i)
+ }
+ register["LR"] = arm64.REGLINK
+ register["DAIF"] = arm64.REG_DAIF
+ register["NZCV"] = arm64.REG_NZCV
+ register["FPSR"] = arm64.REG_FPSR
+ register["FPCR"] = arm64.REG_FPCR
+ register["SPSR_EL1"] = arm64.REG_SPSR_EL1
+ register["ELR_EL1"] = arm64.REG_ELR_EL1
+ register["SPSR_EL2"] = arm64.REG_SPSR_EL2
+ register["ELR_EL2"] = arm64.REG_ELR_EL2
+ register["CurrentEL"] = arm64.REG_CurrentEL
+ register["SP_EL0"] = arm64.REG_SP_EL0
+ register["SPSel"] = arm64.REG_SPSel
+ register["DAIFSet"] = arm64.REG_DAIFSet
+ register["DAIFClr"] = arm64.REG_DAIFClr
+ // Conditional operators, like EQ, NE, etc.
+ register["EQ"] = arm64.COND_EQ
+ register["NE"] = arm64.COND_NE
+ register["HS"] = arm64.COND_HS
+ register["LO"] = arm64.COND_LO
+ register["MI"] = arm64.COND_MI
+ register["PL"] = arm64.COND_PL
+ register["VS"] = arm64.COND_VS
+ register["VC"] = arm64.COND_VC
+ register["HI"] = arm64.COND_HI
+ register["LS"] = arm64.COND_LS
+ register["GE"] = arm64.COND_GE
+ register["LT"] = arm64.COND_LT
+ register["GT"] = arm64.COND_GT
+ register["LE"] = arm64.COND_LE
+ register["AL"] = arm64.COND_AL
+ register["NV"] = arm64.COND_NV
+ // Pseudo-registers.
+ register["SB"] = RSB
+ register["FP"] = RFP
+ register["PC"] = RPC
+ register["SP"] = RSP
+ // Avoid unintentionally clobbering g using R28.
+ delete(register, "R28")
+ register["g"] = arm64.REG_R28
+ registerPrefix := map[string]bool{
+ "F": true,
+ "R": true,
+ "V": true,
+ }
+
+ instructions := make(map[string]int)
+ for i, s := range obj.Anames {
+ instructions[s] = i
+ }
+ for i, s := range arm64.Anames {
+ if i >= obj.A_ARCHSPECIFIC {
+ instructions[s] = i + obj.ABaseARM64
+ }
+ }
+ // Annoying aliases.
+ instructions["B"] = arm64.AB
+ instructions["BL"] = arm64.ABL
+
+ return &Arch{
+ LinkArch: &arm64.Linkarm64,
+ Instructions: instructions,
+ Register: register,
+ RegisterPrefix: registerPrefix,
+ RegisterNumber: arm64RegisterNumber,
+ IsJump: jumpArm64,
+ }
+
+}
+
func archPPC64() *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
// 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) {
+ return parseARMCondition(cond, armLS, armSCOND)
+}
+
+func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
if strings.HasPrefix(cond, ".") {
cond = cond[1:]
}
names := strings.Split(cond, ".")
bits := uint8(0)
for _, name := range names {
- if b, present := armLS[name]; present {
+ if b, present := ls[name]; present {
bits |= b
continue
}
- if b, present := armSCOND[name]; present {
+ if b, present := scond[name]; present {
bits = (bits &^ arm.C_SCOND) | b
continue
}
--- /dev/null
+// 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 ARM64
+// instruction set, to minimize its interaction with the core of the
+// assembler.
+
+package arch
+
+import (
+ "cmd/internal/obj"
+ "cmd/internal/obj/arm64"
+)
+
+var arm64LS = map[string]uint8{
+ "P": arm64.C_XPOST,
+ "W": arm64.C_XPRE,
+}
+
+var arm64Jump = 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,
+ "CBZ": true,
+ "CBZW": true,
+ "CBNZ": true,
+ "CBNZW": true,
+}
+
+func jumpArm64(word string) bool {
+ return arm64Jump[word]
+}
+
+// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is
+// one of the comparison instructions that require special handling.
+func IsARM64CMP(op int) bool {
+ switch op {
+ case arm64.ACMN, arm64.ACMP, arm64.ATST,
+ arm64.ACMNW, arm64.ACMPW, arm64.ATSTW:
+ return true
+ }
+ return false
+}
+
+// IsARM64STLXR reports whether the op (as defined by an arm64.A*
+// constant) is one of the STLXR-like instructions that require special
+// handling.
+func IsARM64STLXR(op int) bool {
+ switch op {
+ case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR:
+ return true
+ }
+ return false
+}
+
+// ARM64Suffix handles the special suffix for the ARM64.
+// It returns a boolean to indicate success; failure means
+// cond was unrecognized.
+func ARM64Suffix(prog *obj.Prog, cond string) bool {
+ if cond == "" {
+ return true
+ }
+ bits, ok := ParseARM64Suffix(cond)
+ if !ok {
+ return false
+ }
+ prog.Scond = bits
+ return true
+}
+
+// ParseARM64Suffix parses the suffix attached to an ARM64 instruction.
+// The input is a single string consisting of period-separated condition
+// codes, such as ".P.W". An initial period is ignored.
+func ParseARM64Suffix(cond string) (uint8, bool) {
+ if cond == "" {
+ return 0, true
+ }
+ return parseARMCondition(cond, arm64LS, nil)
+}
+
+func arm64RegisterNumber(name string, n int16) (int16, bool) {
+ switch name {
+ case "F":
+ if 0 <= n && n <= 31 {
+ return arm64.REG_F0 + n, true
+ }
+ case "R":
+ if 0 <= n && n <= 30 { // not 31
+ return arm64.REG_R0 + n, true
+ }
+ case "V":
+ if 0 <= n && n <= 31 {
+ return arm64.REG_V0 + n, true
+ }
+ }
+ return 0, false
+}
// append adds the Prog to the end of the program-thus-far.
// If doLabel is set, it also defines the labels collect for this Prog.
func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
- if p.arch.Thechar == '5' {
- if !arch.ARMConditionCodes(prog, cond) {
- p.errorf("unrecognized condition code .%q", cond)
+ if cond != "" {
+ switch p.arch.Thechar {
+ case '5':
+ if !arch.ARMConditionCodes(prog, cond) {
+ p.errorf("unrecognized condition code .%q", cond)
+ }
+
+ case '7':
+ if !arch.ARM64Suffix(prog, cond) {
+ p.errorf("unrecognized suffix .%q", cond)
+ }
+
+ default:
+ p.errorf("unrecognized suffix .%q", cond)
}
}
if p.firstProg == nil {
case 1:
target = &a[0]
case 2:
- if p.arch.Thechar == '9' {
- // Special 2-operand jumps.
- target = &a[1]
- prog.From = a[0]
- break
- }
- p.errorf("wrong number of arguments to %s instruction", obj.Aconv(op))
- return
+ // Special 2-operand jumps.
+ target = &a[1]
+ prog.From = a[0]
case 3:
if p.arch.Thechar == '9' {
// Special 3-operand jumps.
}
p.errorf("unrecognized addressing for %s", obj.Aconv(op))
}
+ } else if p.arch.Thechar == '7' && arch.IsARM64CMP(op) {
+ prog.From = a[0]
+ prog.Reg = p.getRegister(prog, op, &a[1])
+ break
}
prog.From = a[0]
prog.To = a[1]
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2]
+ case '7':
+ // ARM64 instructions with one input and two outputs.
+ if arch.IsARM64STLXR(op) {
+ prog.From = a[0]
+ prog.To = a[1]
+ prog.To2 = a[2]
+ break
+ }
+ prog.From = a[0]
+ prog.Reg = p.getRegister(prog, op, &a[1])
+ prog.To = a[2]
case '6', '8':
prog.From = a[0]
prog.From3 = a[1]
parser := newParser("arm")
testOperandParser(t, parser, armOperandTests)
}
+func TestARM64OperandParser(t *testing.T) {
+ parser := newParser("arm64")
+ testOperandParser(t, parser, arm64OperandTests)
+}
func TestPPC64OperandParser(t *testing.T) {
parser := newParser("ppc64")
{"·AddUint32(SB)", "\"\".AddUint32(SB)"},
{"·trunc(SB)", "\"\".trunc(SB)"},
}
+
+var arm64OperandTests = []operandTest{
+ {"$0", "$0"},
+ {"$0.5", "$(0.5)"},
+ {"0(R26)", "(R26)"},
+ {"0(RSP)", "(RSP)"},
+ {"$1", "$1"},
+ {"$-1", "$-1"},
+ {"$1000", "$1000"},
+ {"$1000000000", "$1000000000"},
+ {"$0x7fff3c000", "$34358935552"},
+ {"$1234", "$1234"},
+ {"$~15", "$-16"},
+ {"$16", "$16"},
+ {"-16(RSP)", "-16(RSP)"},
+ {"16(RSP)", "16(RSP)"},
+ {"1(R1)", "1(R1)"},
+ {"-1(R4)", "-1(R4)"},
+ {"18740(R5)", "18740(R5)"},
+ {"$2", "$2"},
+ {"$-24(R4)", "$-24(R4)"},
+ {"-24(RSP)", "-24(RSP)"},
+ {"$24(RSP)", "$24(RSP)"},
+ {"-32(RSP)", "-32(RSP)"},
+ {"$48", "$48"},
+ {"$(-64*1024)(R7)", "$-65536(R7)"},
+ {"$(8-1)", "$7"},
+ {"a+0(FP)", "a(FP)"},
+ {"a1+8(FP)", "a1+8(FP)"},
+ {"·AddInt32(SB)", `"".AddInt32(SB)`},
+ {"runtime·divWVW(SB)", "runtime.divWVW(SB)"},
+ {"$argframe+0(FP)", "$argframe(FP)"},
+ {"$asmcgocall<>(SB)", "$asmcgocall<>(SB)"},
+ {"EQ", "EQ"},
+ {"F29", "F29"},
+ {"F3", "F3"},
+ {"F30", "F30"},
+ {"g", "g"},
+ {"LR", "R30"},
+ {"(LR)", "(R30)"},
+ {"R0", "R0"},
+ {"R10", "R10"},
+ {"R11", "R11"},
+ {"$4503601774854144.0", "$(4503601774854144.0)"},
+ {"$runtime·badsystemstack(SB)", "$runtime.badsystemstack(SB)"},
+ {"ZR", "ZR"},
+ {"(ZR)", "(ZR)"},
+}
for {
tok = p.lex.Next()
if len(operands) == 0 && len(items) == 0 {
- if p.arch.Thechar == '5' && tok == '.' {
+ if (p.arch.Thechar == '5' || p.arch.Thechar == '7') && tok == '.' {
// ARM conditionals.
tok = p.lex.Next()
str := p.lex.Text()