func GoSyntax()

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
}