Commit 1f5a0e8c authored by fanzha02's avatar fanzha02 Committed by Brad Fitzpatrick

cmd/vendor/golang.org/x/arch: pull updates from x repo

Vendor from golang.org/x/arch repo.  Pull in commits that update
arm64, arm, ppc64 and x86 directories (the latest commit 9111c30).

Change-Id: I2b4b3ea9662e69bcf0eeee9c6aba0118175524df
Reviewed-on: https://go-review.googlesource.com/107695
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent c2a53b1b
......@@ -13,6 +13,7 @@ import (
"encoding/hex"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
......@@ -196,7 +197,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
file = f.Name()
f.Seek(start, 0)
f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f)
defer w.Flush()
size = 0
......
......@@ -192,7 +192,7 @@ func parseContinuation(line []byte, enc []byte) []byte {
// describing a text segment that starts at start
// and extends for size bytes.
func writeELF32(f *os.File, size int) error {
f.Seek(0, 0)
f.Seek(0, io.SeekStart)
var hdr elf.Header32
var prog elf.Prog32
var sect elf.Section32
......
......@@ -96,34 +96,24 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
// Move addressing mode into opcode suffix.
suffix := ""
switch inst.Op &^ 15 {
case LDR_EQ, LDRB_EQ, LDRSB_EQ, LDRH_EQ, LDRSH_EQ, STR_EQ, STRB_EQ, STRH_EQ, VLDR_EQ, VSTR_EQ:
mem, _ := inst.Args[1].(Mem)
switch mem.Mode {
case AddrOffset, AddrLDM:
// no suffix
case AddrPreIndex, AddrLDM_WB:
suffix = ".W"
case AddrPostIndex:
suffix = ".P"
case PLD, PLI, PLD_W:
if mem, ok := inst.Args[0].(Mem); ok {
args[0], suffix = memOpTrans(mem)
} else {
panic(fmt.Sprintf("illegal instruction: %v", inst))
}
off := ""
if mem.Offset != 0 {
off = fmt.Sprintf("%#x", mem.Offset)
case LDR_EQ, LDRB_EQ, LDRSB_EQ, LDRH_EQ, LDRSH_EQ, STR_EQ, STRB_EQ, STRH_EQ, VLDR_EQ, VSTR_EQ, LDREX_EQ, LDREXH_EQ, LDREXB_EQ:
if mem, ok := inst.Args[1].(Mem); ok {
args[1], suffix = memOpTrans(mem)
} else {
panic(fmt.Sprintf("illegal instruction: %v", inst))
}
base := fmt.Sprintf("(R%d)", int(mem.Base))
index := ""
if mem.Sign != 0 {
sign := ""
if mem.Sign < 0 {
suffix += ".U"
}
shift := ""
if mem.Count != 0 {
shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count)
}
index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
case SWP_EQ, SWP_B_EQ, STREX_EQ, STREXB_EQ, STREXH_EQ:
if mem, ok := inst.Args[2].(Mem); ok {
args[2], suffix = memOpTrans(mem)
} else {
panic(fmt.Sprintf("illegal instruction: %v", inst))
}
args[1] = off + base + index
}
// Reverse args, placing dest last.
......@@ -135,35 +125,35 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
case SMLAWT_EQ, SMLAWB_EQ, MLA_EQ, MLA_S_EQ, MLS_EQ, SMMLA_EQ, SMMLS_EQ, SMLABB_EQ, SMLATB_EQ, SMLABT_EQ, SMLATT_EQ, SMLAD_EQ, SMLAD_X_EQ, SMLSD_EQ, SMLSD_X_EQ:
args = []string{args[1], args[2], args[0], args[3]}
}
// For STREX like instructions, the memory operands comes first.
switch inst.Op &^ 15 {
case STREX_EQ, STREXB_EQ, STREXH_EQ, SWP_EQ, SWP_B_EQ:
args = []string{args[1], args[0], args[2]}
}
// special process for FP instructions
op, args = fpTrans(&inst, op, args)
// LDR/STR like instructions -> MOV like
switch inst.Op &^ 15 {
case MOV_EQ:
op = "MOVW" + op[3:]
case LDR_EQ:
case LDR_EQ, MSR_EQ, MRS_EQ:
op = "MOVW" + op[3:] + suffix
case LDRB_EQ:
case VMRS_EQ, VMSR_EQ:
op = "MOVW" + op[4:] + suffix
case LDRB_EQ, UXTB_EQ:
op = "MOVBU" + op[4:] + suffix
case LDRSB_EQ:
op = "MOVBS" + op[5:] + suffix
case LDRH_EQ:
case SXTB_EQ:
op = "MOVBS" + op[4:] + suffix
case LDRH_EQ, UXTH_EQ:
op = "MOVHU" + op[4:] + suffix
case LDRSH_EQ:
op = "MOVHS" + op[5:] + suffix
case VLDR_EQ:
switch {
case strings.HasPrefix(args[1], "D"): // VLDR.F64
op = "MOVD" + op[4:] + suffix
args[1] = "F" + args[1][1:] // Dx -> Fx
case strings.HasPrefix(args[1], "S"): // VLDR.F32
op = "MOVF" + op[4:] + suffix
if inst.Args[0].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
args[1] = fmt.Sprintf("F%d", (inst.Args[0].(Reg)-S0)/2)
}
default:
panic(fmt.Sprintf("wrong FP register: %v", inst))
}
case SXTH_EQ:
op = "MOVHS" + op[4:] + suffix
case STR_EQ:
op = "MOVW" + op[3:] + suffix
args[0], args[1] = args[1], args[0]
......@@ -174,19 +164,9 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
op = "MOVH" + op[4:] + suffix
args[0], args[1] = args[1], args[0]
case VSTR_EQ:
switch {
case strings.HasPrefix(args[1], "D"): // VSTR.F64
op = "MOVD" + op[4:] + suffix
args[1] = "F" + args[1][1:] // Dx -> Fx
case strings.HasPrefix(args[1], "S"): // VSTR.F32
op = "MOVF" + op[4:] + suffix
if inst.Args[0].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
args[1] = fmt.Sprintf("F%d", (inst.Args[0].(Reg)-S0)/2)
}
default:
panic(fmt.Sprintf("wrong FP register: %v", inst))
}
args[0], args[1] = args[1], args[0]
default:
op = op + suffix
}
if args != nil {
......@@ -266,3 +246,153 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
}
return strings.ToUpper(arg.String())
}
// convert memory operand from GNU syntax to Plan 9 syntax, for example,
// [r5] -> (R5)
// [r6, #4080] -> 0xff0(R6)
// [r2, r0, ror #1] -> (R2)(R0@>1)
// inst [r2, -r0, ror #1] -> INST.U (R2)(R0@>1)
// input:
// a memory operand
// return values:
// corresponding memory operand in Plan 9 syntax
// .W/.P/.U suffix
func memOpTrans(mem Mem) (string, string) {
suffix := ""
switch mem.Mode {
case AddrOffset, AddrLDM:
// no suffix
case AddrPreIndex, AddrLDM_WB:
suffix = ".W"
case AddrPostIndex:
suffix = ".P"
}
off := ""
if mem.Offset != 0 {
off = fmt.Sprintf("%#x", mem.Offset)
}
base := fmt.Sprintf("(R%d)", int(mem.Base))
index := ""
if mem.Sign != 0 {
sign := ""
if mem.Sign < 0 {
suffix += ".U"
}
shift := ""
if mem.Count != 0 {
shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count)
}
index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
}
return off + base + index, suffix
}
type goFPInfo struct {
op Op
transArgs []int // indexes of arguments which need transformation
gnuName string // instruction name in GNU syntax
goName string // instruction name in Plan 9 syntax
}
var fpInst []goFPInfo = []goFPInfo{
{VADD_EQ_F32, []int{2, 1, 0}, "VADD", "ADDF"},
{VADD_EQ_F64, []int{2, 1, 0}, "VADD", "ADDD"},
{VSUB_EQ_F32, []int{2, 1, 0}, "VSUB", "SUBF"},
{VSUB_EQ_F64, []int{2, 1, 0}, "VSUB", "SUBD"},
{VMUL_EQ_F32, []int{2, 1, 0}, "VMUL", "MULF"},
{VMUL_EQ_F64, []int{2, 1, 0}, "VMUL", "MULD"},
{VNMUL_EQ_F32, []int{2, 1, 0}, "VNMUL", "NMULF"},
{VNMUL_EQ_F64, []int{2, 1, 0}, "VNMUL", "NMULD"},
{VMLA_EQ_F32, []int{2, 1, 0}, "VMLA", "MULAF"},
{VMLA_EQ_F64, []int{2, 1, 0}, "VMLA", "MULAD"},
{VMLS_EQ_F32, []int{2, 1, 0}, "VMLS", "MULSF"},
{VMLS_EQ_F64, []int{2, 1, 0}, "VMLS", "MULSD"},
{VNMLA_EQ_F32, []int{2, 1, 0}, "VNMLA", "NMULAF"},
{VNMLA_EQ_F64, []int{2, 1, 0}, "VNMLA", "NMULAD"},
{VNMLS_EQ_F32, []int{2, 1, 0}, "VNMLS", "NMULSF"},
{VNMLS_EQ_F64, []int{2, 1, 0}, "VNMLS", "NMULSD"},
{VDIV_EQ_F32, []int{2, 1, 0}, "VDIV", "DIVF"},
{VDIV_EQ_F64, []int{2, 1, 0}, "VDIV", "DIVD"},
{VNEG_EQ_F32, []int{1, 0}, "VNEG", "NEGF"},
{VNEG_EQ_F64, []int{1, 0}, "VNEG", "NEGD"},
{VABS_EQ_F32, []int{1, 0}, "VABS", "ABSF"},
{VABS_EQ_F64, []int{1, 0}, "VABS", "ABSD"},
{VSQRT_EQ_F32, []int{1, 0}, "VSQRT", "SQRTF"},
{VSQRT_EQ_F64, []int{1, 0}, "VSQRT", "SQRTD"},
{VCMP_EQ_F32, []int{1, 0}, "VCMP", "CMPF"},
{VCMP_EQ_F64, []int{1, 0}, "VCMP", "CMPD"},
{VCMP_E_EQ_F32, []int{1, 0}, "VCMP.E", "CMPF"},
{VCMP_E_EQ_F64, []int{1, 0}, "VCMP.E", "CMPD"},
{VLDR_EQ, []int{1}, "VLDR", "MOV"},
{VSTR_EQ, []int{1}, "VSTR", "MOV"},
{VMOV_EQ_F32, []int{1, 0}, "VMOV", "MOVF"},
{VMOV_EQ_F64, []int{1, 0}, "VMOV", "MOVD"},
{VMOV_EQ_32, []int{1, 0}, "VMOV", "MOVW"},
{VMOV_EQ, []int{1, 0}, "VMOV", "MOVW"},
{VCVT_EQ_F64_F32, []int{1, 0}, "VCVT", "MOVFD"},
{VCVT_EQ_F32_F64, []int{1, 0}, "VCVT", "MOVDF"},
{VCVT_EQ_F32_U32, []int{1, 0}, "VCVT", "MOVWF.U"},
{VCVT_EQ_F32_S32, []int{1, 0}, "VCVT", "MOVWF"},
{VCVT_EQ_S32_F32, []int{1, 0}, "VCVT", "MOVFW"},
{VCVT_EQ_U32_F32, []int{1, 0}, "VCVT", "MOVFW.U"},
{VCVT_EQ_F64_U32, []int{1, 0}, "VCVT", "MOVWD.U"},
{VCVT_EQ_F64_S32, []int{1, 0}, "VCVT", "MOVWD"},
{VCVT_EQ_S32_F64, []int{1, 0}, "VCVT", "MOVDW"},
{VCVT_EQ_U32_F64, []int{1, 0}, "VCVT", "MOVDW.U"},
}
// convert FP instructions from GNU syntax to Plan 9 syntax, for example,
// vadd.f32 s0, s3, s4 -> ADDF F0, S3, F2
// vsub.f64 d0, d2, d4 -> SUBD F0, F2, F4
// vldr s2, [r11] -> MOVF (R11), F1
// inputs: instruction name and arguments in GNU syntax
// return values: corresponding instruction name and arguments in Plan 9 syntax
func fpTrans(inst *Inst, op string, args []string) (string, []string) {
for _, fp := range fpInst {
if inst.Op&^15 == fp.op {
// remove gnu syntax suffixes
op = strings.Replace(op, ".F32", "", -1)
op = strings.Replace(op, ".F64", "", -1)
op = strings.Replace(op, ".S32", "", -1)
op = strings.Replace(op, ".U32", "", -1)
op = strings.Replace(op, ".32", "", -1)
// compose op name
if fp.op == VLDR_EQ || fp.op == VSTR_EQ {
switch {
case strings.HasPrefix(args[fp.transArgs[0]], "D"):
op = "MOVD" + op[len(fp.gnuName):]
case strings.HasPrefix(args[fp.transArgs[0]], "S"):
op = "MOVF" + op[len(fp.gnuName):]
default:
panic(fmt.Sprintf("wrong FP register: %v", inst))
}
} else {
op = fp.goName + op[len(fp.gnuName):]
}
// transform registers
for ix, ri := range fp.transArgs {
switch {
case strings.HasSuffix(args[ri], "[1]"): // MOVW Rx, Dy[1]
break
case strings.HasSuffix(args[ri], "[0]"): // Dx[0] -> Fx
args[ri] = strings.Replace(args[ri], "[0]", "", -1)
fallthrough
case strings.HasPrefix(args[ri], "D"): // Dx -> Fx
args[ri] = "F" + args[ri][1:]
case strings.HasPrefix(args[ri], "S"):
if inst.Args[ix].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
args[ri] = fmt.Sprintf("F%d", (inst.Args[ix].(Reg)-S0)/2)
}
case strings.HasPrefix(args[ri], "$"): // CMPF/CMPD $0, Fx
break
case strings.HasPrefix(args[ri], "R"): // MOVW Rx, Dy[1]
break
default:
panic(fmt.Sprintf("wrong FP register: %v", inst))
}
}
break
}
}
return op, args
}
......@@ -7,12 +7,14 @@ package arm64asm
import (
"encoding/hex"
"io/ioutil"
"path/filepath"
"strings"
"testing"
)
func TestDecode(t *testing.T) {
data, err := ioutil.ReadFile("testdata/cases.txt")
func testDecode(t *testing.T, syntax string) {
input := filepath.Join("testdata", syntax+"cases.txt")
data, err := ioutil.ReadFile(input)
if err != nil {
t.Fatal(err)
}
......@@ -25,7 +27,7 @@ func TestDecode(t *testing.T) {
if line == "" || strings.HasPrefix(line, "#") {
continue
}
f := strings.SplitN(line, "\t", 3)
f := strings.SplitN(line, "\t", 2)
i := strings.Index(f[0], "|")
if i < 0 {
t.Errorf("parsing %q: missing | separator", f[0])
......@@ -39,7 +41,7 @@ func TestDecode(t *testing.T) {
t.Errorf("parsing %q: %v", f[0], err)
continue
}
syntax, asm := f[1], f[2]
asm := f[1]
inst, decodeErr := Decode(code)
if decodeErr != nil && decodeErr != errUnknown {
// Some rarely used system instructions are not supported
......@@ -71,8 +73,16 @@ func TestDecode(t *testing.T) {
if strings.Replace(out, " ", "", -1) != strings.Replace(asm, " ", "", -1) && !hasPrefix(asm, Todo...) {
// Exclude MSR since GNU objdump result is incorrect. eg. 0xd504431f msr s0_4_c4_c3_0, xzr
if !strings.HasSuffix(asm, " nv") && !strings.HasPrefix(asm, "msr") {
t.Errorf("Decode(%s) [%s] = %s, want %s", f[0], syntax, out, asm)
t.Errorf("Decode(%s) [%s] = %s, want %s", strings.Trim(f[0], "|"), syntax, out, asm)
}
}
}
}
func TestDecodeGNUSyntax(t *testing.T) {
testDecode(t, "gnu")
}
func TestDecodeGoSyntax(t *testing.T) {
testDecode(t, "plan9")
}
......@@ -14,11 +14,13 @@ import (
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
......@@ -220,7 +222,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
file = f.Name()
f.Seek(start, 0)
f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f)
defer w.Flush()
size = 0
......@@ -565,9 +567,10 @@ func hexCases(t *testing.T, encoded string) func(func([]byte)) {
// testdataCases generates the test cases recorded in testdata/cases.txt.
// It only uses the inputs; it ignores the answers recorded in that file.
func testdataCases(t *testing.T) func(func([]byte)) {
func testdataCases(t *testing.T, syntax string) func(func([]byte)) {
var codes [][]byte
data, err := ioutil.ReadFile("testdata/cases.txt")
input := filepath.Join("testdata", syntax+"cases.txt")
data, err := ioutil.ReadFile(input)
if err != nil {
t.Fatal(err)
}
......
......@@ -536,8 +536,13 @@ type MemExtend struct {
Base RegSP
Index Reg
Extend ExtShift
// Amount indicates the index shift amount (but also see ShiftMustBeZero field below).
Amount uint8
Absent bool
// ShiftMustBeZero is set to true when the shift amount must be 0, even if the
// Amount field is not 0. In GNU syntax, a #0 shift amount is printed if Amount
// is not 0 but ShiftMustBeZero is true; #0 is not printed if Amount is 0 and
// ShiftMustBeZero is true. Both cases represent shift by 0 bit.
ShiftMustBeZero bool
}
func (MemExtend) isArg() {}
......@@ -545,7 +550,7 @@ func (MemExtend) isArg() {}
func (m MemExtend) String() string {
Rbase := m.Base.String()
RIndex := m.Index.String()
if m.Absent {
if m.ShiftMustBeZero {
if m.Amount != 0 {
return fmt.Sprintf("[%s,%s,%s #0]", Rbase, RIndex, m.Extend.String())
} else {
......
......@@ -9,10 +9,15 @@ import (
"testing"
)
func TestObjdumpARM64Testdata(t *testing.T) { testObjdumpARM64(t, testdataCases(t)) }
func TestObjdumpARM64Manual(t *testing.T) { testObjdumpARM64(t, hexCases(t, objdumpManualTests)) }
func TestObjdumpARM64Cond(t *testing.T) { testObjdumpARM64(t, condCases(t)) }
func TestObjdumpARM64(t *testing.T) { testObjdumpARM64(t, JSONCases(t)) }
func TestObjdumpARM64TestDecodeGNUSyntaxdata(t *testing.T) {
testObjdumpARM64(t, testdataCases(t, "gnu"))
}
func TestObjdumpARM64TestDecodeGoSyntaxdata(t *testing.T) {
testObjdumpARM64(t, testdataCases(t, "plan9"))
}
func TestObjdumpARM64Manual(t *testing.T) { testObjdumpARM64(t, hexCases(t, objdumpManualTests)) }
func TestObjdumpARM64Cond(t *testing.T) { testObjdumpARM64(t, condCases(t)) }
func TestObjdumpARM64(t *testing.T) { testObjdumpARM64(t, JSONCases(t)) }
// objdumpManualTests holds test cases that will be run by TestObjdumpARMManual.
// If you are debugging a few cases that turned up in a longer run, it can be useful
......
......@@ -232,7 +232,7 @@ func parseContinuation(line []byte, enc []byte) []byte {
// writeELF64 writes an ELF64 header to the file, describing a text
// segment that starts at start (0x8000) and extends for size bytes.
func writeELF64(f *os.File, size int) error {
f.Seek(0, 0)
f.Seek(0, io.SeekStart)
var hdr elf.Header64
var prog elf.Prog64
var sect elf.Section64
......
......@@ -53,7 +53,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
// Move addressing mode into opcode suffix.
suffix := ""
switch inst.Op {
case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH, STUR, STURB, STURH, LD1:
case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH, STUR, STURB, STURH, LD1, ST1:
switch mem := inst.Args[1].(type) {
case MemImmediate:
switch mem.Mode {
......@@ -114,6 +114,8 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
rno = int(a)
case RegisterWithArrangementAndIndex:
op = "VMOV"
case RegisterWithArrangement:
op = "VMOV"
}
if rno >= 0 && rno <= int(WZR) {
op = "MOVW"
......@@ -133,6 +135,12 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
}
if rno <= uint16(WZR) {
op = "MOVWU" + suffix
} else if rno >= uint16(S0) && rno <= uint16(S31) {
op = "FMOVS" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = "FMOVD" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else {
op = "MOVD" + suffix
}
......@@ -173,6 +181,12 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
}
if rno <= uint16(WZR) {
op = "MOVW" + suffix
} else if rno >= uint16(S0) && rno <= uint16(S31) {
op = "FMOVS" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = "FMOVD" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else {
op = "MOVD" + suffix
}
......@@ -230,6 +244,15 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
}
args[1], args[2], args[3] = args[3], args[1], args[2]
case LDAXP, LDXP:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
fallthrough
case STP, LDP:
args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
args[1] = args[2]
......@@ -239,8 +262,21 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
} else if op == "LDP" {
op = op + suffix
return op + " " + args[1] + ", " + args[0]
} else if op == "LDAXP" || op == "LDXP" || op == "LDAXPW" || op == "LDXPW" {
return op + " " + args[1] + ", " + args[0]
}
case STLXP, STXP:
if r, ok := inst.Args[1].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[1] = fmt.Sprintf("(%s, %s)", args[1], args[2])
args[2] = args[3]
return op + " " + args[1] + ", " + args[2] + ", " + args[0]
case FCCMP, FCCMPE:
args[0], args[1] = args[1], args[0]
fallthrough
......@@ -251,7 +287,10 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
}
fallthrough
case FADD, FSUB, FMUL, FNMUL, FDIV, FMAX, FMIN, FMAXNM, FMINNM, FCSEL:
case FADD, FSUB, FMUL, FNMUL, FDIV, FMAX, FMIN, FMAXNM, FMINNM, FCSEL, FMADD, FMSUB, FNMADD, FNMSUB:
if strings.HasSuffix(op, "MADD") || strings.HasSuffix(op, "MSUB") {
args[2], args[3] = args[3], args[2]
}
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) {
......@@ -337,6 +376,19 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
addr := int64(inst.Args[1].(PCRel))
args[1] = fmt.Sprintf("%d(PC)", addr)
case MSR:
args[0] = inst.Args[0].String()
case ST1:
op = fmt.Sprintf("V%s", op) + suffix
args[0], args[1] = args[1], args[0]
case LD1:
op = fmt.Sprintf("V%s", op) + suffix
case UMOV:
op = "VMOV"
default:
index := sort.SearchStrings(noSuffixOpSet, op)
if !(index < len(noSuffixOpSet) && noSuffixOpSet[index] == op) {
......@@ -350,6 +402,9 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
op = fmt.Sprintf("V%s", op)
}
if rno >= int(B0) && rno <= int(Q31) && !strings.HasPrefix(op, "F") {
op = fmt.Sprintf("V%s", op)
}
if rno >= 0 && rno <= int(WZR) {
// Add "w" to opcode suffix.
op += "W"
......@@ -381,6 +436,10 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text
// No need add "W" to opcode suffix.
// Opcode must be inserted in ascending order.
var noSuffixOpSet = strings.Fields(`
AESD
AESE
AESIMC
AESMC
CRC32B
CRC32CB
CRC32CH
......@@ -393,8 +452,19 @@ LDARB
LDARH
LDAXRB
LDAXRH
LDTRH
LDXRB
LDXRH
SHA1C
SHA1H
SHA1M
SHA1P
SHA1SU0
SHA1SU1
SHA256H
SHA256H2
SHA256SU0
SHA256SU1
`)
func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
......@@ -423,9 +493,14 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
regno := uint16(a) & 31
if regenum >= uint16(B0) && regenum <= uint16(D31) {
// FP registers are the same ones as SIMD registers
// Print Fn for scalar variant to align with assembler (e.g., FCVT)
return fmt.Sprintf("F%d", regno)
if strings.HasPrefix(inst.Op.String(), "F") || strings.HasSuffix(inst.Op.String(), "CVTF") {
// FP registers are the same ones as SIMD registers
// Print Fn for scalar variant to align with assembler (e.g., FCVT, SCVTF, UCVTF, etc.)
return fmt.Sprintf("F%d", regno)
} else {
return fmt.Sprintf("V%d", regno)
}
} else if regenum >= uint16(Q0) && regenum <= uint16(Q31) {
// Print Vn to align with assembler (e.g., SHA256H)
return fmt.Sprintf("V%d", regno)
......@@ -503,7 +578,6 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
case MemExtend:
base := ""
index := ""
extend := ""
indexreg := ""
regno := uint16(a.Base) & 31
if regno == 31 {
......@@ -517,15 +591,28 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
} else {
indexreg = fmt.Sprintf("R%d", regno)
}
if a.Extend == lsl {
if a.Amount != 0 {
extend = fmt.Sprintf("<<%d", a.Amount)
// a.Amount indicates the index shift amount, encoded in "S" field.
// a.ShiftMustBeZero is set true when the index shift amount must be 0,
// even if the a.Amount field is not 0.
// When a.ShiftMustBeZero is ture, GNU syntax prints #0 shift amount if
// "S" equals to 1, or does not print #0 shift amount if "S" equals to 0.
// Go syntax should never print a zero index shift amount.
if a.Amount != 0 && !a.ShiftMustBeZero {
index = fmt.Sprintf("(%s<<%d)", indexreg, a.Amount)
} else {
index = fmt.Sprintf("(%s)", indexreg)
}
} else {
extend = "unimplemented!"
if a.Amount != 0 && !a.ShiftMustBeZero {
index = fmt.Sprintf("(%s.%s<<%d)", indexreg, a.Extend.String(), a.Amount)
} else {
index = fmt.Sprintf("(%s.%s)", indexreg, a.Extend.String())
}
}
index = indexreg + extend
return index + base
return base + index
case Cond:
switch arg.String() {
......@@ -592,7 +679,7 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
result := a.r.String()
arrange := a.a.String()
result += arrange
if a.cnt > 0 {
if a.cnt > 1 {
result = "[" + result
for i := 1; i < int(a.cnt); i++ {
cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
......@@ -605,6 +692,10 @@ func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg
case Systemreg:
return fmt.Sprintf("$%d", uint32(a.op0&1)<<14|uint32(a.op1&7)<<11|uint32(a.cn&15)<<7|uint32(a.cm&15)<<3|uint32(a.op2)&7)
case Imm_prfop:
if strings.Contains(a.String(), "#") {
return fmt.Sprintf("$%d", a)
}
}
return strings.ToUpper(arg.String())
......
go test command:
cd ..; go test -run 'ObjdumpARM64Cond' -v -timeout 10h -long 2>&1 | tee log
cd ..; go test -run 'ObjdumpARM64Testdata' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64TestGUNSyntaxdata' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64TestGoSyntaxdata' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'ObjdumpARM64Manual' -v -timeout 10h -long 2>&1 | tee -a log
cd ..; go test -run 'TestDecode'
cd ..; go test -run 'TestDecodeGNUSyntax'
cd ..; go test -run 'TestDecodeGoSyntax'
cd ..; go test -run '.*'
......@@ -14,6 +14,7 @@ import (
"encoding/hex"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
......@@ -194,7 +195,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
file = f.Name()
f.Seek(start, 0)
f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f)
defer w.Flush()
size = 0
......
......@@ -188,7 +188,7 @@ func parseContinuation(line []byte, enc []byte) []byte {
// describing a text segment that starts at start
// and extends for size bytes.
func writeELF64(f *os.File, size int) error {
f.Seek(0, 0)
f.Seek(0, io.SeekStart)
var hdr elf.Header64
var prog elf.Prog64
var sect elf.Section64
......
......@@ -12,6 +12,7 @@ import (
"encoding/hex"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
......@@ -194,7 +195,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
file = f.Name()
f.Seek(start, 0)
f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f)
defer w.Flush()
size = 0
......
......@@ -176,7 +176,7 @@ func parseContinuation(line []byte, enc []byte) []byte {
// describing a text segment that starts at start
// and extends for size bytes.
func writeELF32(f *os.File, size int) error {
f.Seek(0, 0)
f.Seek(0, io.SeekStart)
var hdr elf.Header32
var prog elf.Prog32
var sect elf.Section32
......@@ -246,7 +246,7 @@ func writeELF32(f *os.File, size int) error {
// describing a text segment that starts at start
// and extends for size bytes.
func writeELF64(f *os.File, size int) error {
f.Seek(0, 0)
f.Seek(0, io.SeekStart)
var hdr elf.Header64
var prog elf.Prog64
var sect elf.Section64
......
......@@ -15,26 +15,26 @@
{
"canonical": "golang.org/x/arch/x86/x86asm",
"local": "golang.org/x/arch/x86/x86asm",
"revision": "98fd8d9907002617e6000a77c0740a72947ca1c2",
"revisionTime": "2017-12-26T02:13:20Z"
"revision": "5099b4b992f2813e39cfe2623c6f638718bd0fc6",
"revisionTime": "2018-04-06T10:28:20Z"
},
{
"canonical": "golang.org/x/arch/arm/armasm",
"local": "golang.org/x/arch/arm/armasm",
"revision": "98fd8d9907002617e6000a77c0740a72947ca1c2",
"revisionTime": "2017-12-26T02:13:20Z"
"revision": "5099b4b992f2813e39cfe2623c6f638718bd0fc6",
"revisionTime": "2018-04-06T10:28:20Z"
},
{
"canonical": "golang.org/x/arch/ppc64/ppc64asm",
"local": "golang.org/x/arch/ppc64/ppc64asm",
"revision": "98fd8d9907002617e6000a77c0740a72947ca1c2",
"revisionTime": "2017-12-26T02:13:20Z"
"revision": "5099b4b992f2813e39cfe2623c6f638718bd0fc6",
"revisionTime": "2018-04-06T10:28:20Z"
},
{
"canonical": "golang.org/x/arch/arm64/arm6464asm",
"local": "golang.org/x/arch/arm64/arm64asm",
"revision": "98fd8d9907002617e6000a77c0740a72947ca1c2",
"revisionTime": "2017-12-26T02:13:20Z"
"revision": "9111c30535f37e70dcaf5956d34b03233f90f3b6",
"revisionTime": "2018-03-13T04:07:09Z"
}
]
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment