in arm64/arm64asm/plan9x.go [24:467]
func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
if symname == nil {
symname = func(uint64) (string, uint64) { return "", 0 }
}
var args []string
for _, a := range inst.Args {
if a == nil {
break
}
args = append(args, plan9Arg(&inst, pc, symname, a))
}
op := inst.Op.String()
switch inst.Op {
case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW:
// Check for PC-relative load.
if offset, ok := inst.Args[1].(PCRel); ok {
addr := pc + uint64(offset)
if _, ok := inst.Args[0].(Reg); !ok {
break
}
if s, base := symname(addr); s != "" && addr == base {
args[1] = fmt.Sprintf("$%s(SB)", s)
}
}
}
// Move addressing mode into opcode suffix.
suffix := ""
switch inst.Op {
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 {
case AddrOffset:
// no suffix
case AddrPreIndex:
suffix = ".W"
case AddrPostIndex, AddrPostReg:
suffix = ".P"
}
}
case STP, LDP:
switch mem := inst.Args[2].(type) {
case MemImmediate:
switch mem.Mode {
case AddrOffset:
// no suffix
case AddrPreIndex:
suffix = ".W"
case AddrPostIndex:
suffix = ".P"
}
}
}
switch inst.Op {
case BL:
return "CALL " + args[0]
case BLR:
r := inst.Args[0].(Reg)
regno := uint16(r) & 31
return fmt.Sprintf("CALL (R%d)", regno)
case RET:
if r, ok := inst.Args[0].(Reg); ok && r == X30 {
return "RET"
}
case B:
if cond, ok := inst.Args[0].(Cond); ok {
return "B" + cond.String() + " " + args[1]
}
return "JMP" + " " + args[0]
case BR:
r := inst.Args[0].(Reg)
regno := uint16(r) & 31
return fmt.Sprintf("JMP (R%d)", regno)
case MOV:
rno := -1
switch a := inst.Args[0].(type) {
case Reg:
rno = int(a)
case RegSP:
rno = int(a)
case RegisterWithArrangementAndIndex:
op = "VMOV"
case RegisterWithArrangement:
op = "VMOV"
}
if rno >= 0 && rno <= int(WZR) {
op = "MOVW"
} else if rno >= int(X0) && rno <= int(XZR) {
op = "MOVD"
}
if _, ok := inst.Args[1].(RegisterWithArrangementAndIndex); ok {
op = "VMOV"
}
case LDR, LDUR:
var rno uint16
if r, ok := inst.Args[0].(Reg); ok {
rno = uint16(r)
} else {
rno = uint16(inst.Args[0].(RegSP))
}
if rno <= uint16(WZR) {
op = "MOVWU" + suffix
} else if rno >= uint16(B0) && rno <= uint16(B31) {
op = "FMOVB" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else if rno >= uint16(H0) && rno <= uint16(H31) {
op = "FMOVH" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} 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 if rno >= uint16(Q0) && rno <= uint16(Q31) {
op = "FMOVQ" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else {
op = "MOVD" + suffix
}
case LDRB:
op = "MOVBU" + suffix
case LDRH:
op = "MOVHU" + suffix
case LDRSW:
op = "MOVW" + suffix
case LDRSB:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op = "MOVBW" + suffix
} else {
op = "MOVB" + suffix
}
}
case LDRSH:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op = "MOVHW" + suffix
} else {
op = "MOVH" + suffix
}
}
case STR, STUR:
var rno uint16
if r, ok := inst.Args[0].(Reg); ok {
rno = uint16(r)
} else {
rno = uint16(inst.Args[0].(RegSP))
}
if rno <= uint16(WZR) {
op = "MOVW" + suffix
} else if rno >= uint16(B0) && rno <= uint16(B31) {
op = "FMOVB" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else if rno >= uint16(H0) && rno <= uint16(H31) {
op = "FMOVH" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} 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 if rno >= uint16(Q0) && rno <= uint16(Q31) {
op = "FMOVQ" + suffix
args[0] = fmt.Sprintf("F%d", rno&31)
} else {
op = "MOVD" + suffix
}
args[0], args[1] = args[1], args[0]
case STRB, STURB:
op = "MOVB" + suffix
args[0], args[1] = args[1], args[0]
case STRH, STURH:
op = "MOVH" + suffix
args[0], args[1] = args[1], args[0]
case TBNZ, TBZ:
args[0], args[1], args[2] = args[2], args[0], args[1]
case MADD, MSUB, SMADDL, SMSUBL, UMADDL, UMSUBL:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[2], args[3] = args[3], args[2]
case STLR:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[0], args[1] = args[1], args[0]
case STLRB, STLRH:
args[0], args[1] = args[1], args[0]
case STLXR, STXR:
if r, ok := inst.Args[1].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[1], args[2] = args[2], args[1]
case STLXRB, STLXRH, STXRB, STXRH:
args[1], args[2] = args[2], args[1]
case BFI, BFXIL, SBFIZ, SBFX, UBFIZ, UBFX:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
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"
}
}
args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
args[1] = args[2]
return op + " " + args[1] + ", " + args[0]
case STP, LDP:
args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
args[1] = args[2]
rno, ok := inst.Args[0].(Reg)
if !ok {
rno = Reg(inst.Args[0].(RegSP))
}
if rno <= WZR {
op = op + "W"
} else if rno >= S0 && rno <= S31 {
op = "F" + op + "S"
} else if rno >= D0 && rno <= D31 {
op = "F" + op + "D"
} else if rno >= Q0 && rno <= Q31 {
op = "F" + op + "Q"
}
op = op + suffix
if inst.Op.String() == "STP" {
return op + " " + args[0] + ", " + args[1]
} else {
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
case FCMP, FCMPE:
if _, ok := inst.Args[1].(Imm); ok {
args[1] = "$(0.0)"
}
fallthrough
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) {
op = fmt.Sprintf("%sS", op)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
}
}
case FCVT:
for i := 1; i >= 0; i-- {
if r, ok := inst.Args[i].(Reg); ok {
rno := uint16(r)
if rno >= uint16(H0) && rno <= uint16(H31) {
op = fmt.Sprintf("%sH", op)
} else if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
}
}
}
case FABS, FNEG, FSQRT, FRINTN, FRINTP, FRINTM, FRINTZ, FRINTA, FRINTX, FRINTI:
if r, ok := inst.Args[1].(Reg); ok {
rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
}
}
case FCVTZS, FCVTZU, SCVTF, UCVTF:
if _, ok := inst.Args[2].(Imm); !ok {
for i := 1; i >= 0; i-- {
if r, ok := inst.Args[i].(Reg); ok {
rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
} else if rno <= uint16(WZR) {
op += "W"
}
}
}
}
case FMOV:
for i := 0; i <= 1; i++ {
if r, ok := inst.Args[i].(Reg); ok {
rno := uint16(r)
if rno >= uint16(S0) && rno <= uint16(S31) {
op = fmt.Sprintf("%sS", op)
break
} else if rno >= uint16(D0) && rno <= uint16(D31) {
op = fmt.Sprintf("%sD", op)
break
}
}
}
case SYSL:
op1 := int(inst.Args[1].(Imm).Imm)
cn := int(inst.Args[2].(Imm_c))
cm := int(inst.Args[3].(Imm_c))
op2 := int(inst.Args[4].(Imm).Imm)
sysregno := int32(op1<<16 | cn<<12 | cm<<8 | op2<<5)
args[1] = fmt.Sprintf("$%d", sysregno)
return op + " " + args[1] + ", " + args[0]
case CBNZ, CBZ:
if r, ok := inst.Args[0].(Reg); ok {
rno := uint16(r)
if rno <= uint16(WZR) {
op += "W"
}
}
args[0], args[1] = args[1], args[0]
case ADR, ADRP:
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"
case NOP:
op = "NOOP"
default:
index := sort.SearchStrings(noSuffixOpSet, op)
if !(index < len(noSuffixOpSet) && noSuffixOpSet[index] == op) {
rno := -1
switch a := inst.Args[0].(type) {
case Reg:
rno = int(a)
case RegSP:
rno = int(a)
case RegisterWithArrangement:
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"
}
}
op = op + suffix
}
// conditional instructions, replace args.
if _, ok := inst.Args[3].(Cond); ok {
if _, ok := inst.Args[2].(Reg); ok {
args[1], args[2] = args[2], args[1]
} else {
args[0], args[2] = args[2], args[0]
}
}
// Reverse args, placing dest last.
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
args[i], args[j] = args[j], args[i]
}
if args != nil {
op += " " + strings.Join(args, ", ")
}
return op
}