func plan9Arg()

in arm64/arm64asm/plan9x.go [509:742]


func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
	switch a := arg.(type) {
	case Imm:
		return fmt.Sprintf("$%d", uint32(a.Imm))

	case Imm64:
		return fmt.Sprintf("$%d", int64(a.Imm))

	case ImmShift:
		if a.shift == 0 {
			return fmt.Sprintf("$%d", a.imm)
		}
		return fmt.Sprintf("$(%d<<%d)", a.imm, a.shift)

	case PCRel:
		addr := int64(pc) + int64(a)
		if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
			return fmt.Sprintf("%s(SB)", s)
		}
		return fmt.Sprintf("%d(PC)", a/4)

	case Reg:
		regenum := uint16(a)
		regno := uint16(a) & 31

		if regenum >= uint16(B0) && regenum <= uint16(Q31) {
			if strings.HasPrefix(inst.Op.String(), "F") || strings.HasSuffix(inst.Op.String(), "CVTF") || fOpsWithoutFPrefix[inst.Op] {
				// 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 {
				// Print Vn to align with assembler (e.g., SHA256H)
				return fmt.Sprintf("V%d", regno)
			}

		}
		if regno == 31 {
			return "ZR"
		}
		return fmt.Sprintf("R%d", regno)

	case RegSP:
		regno := uint16(a) & 31
		if regno == 31 {
			return "RSP"
		}
		return fmt.Sprintf("R%d", regno)

	case RegExtshiftAmount:
		reg := ""
		regno := uint16(a.reg) & 31
		if regno == 31 {
			reg = "ZR"
		} else {
			reg = fmt.Sprintf("R%d", uint16(a.reg)&31)
		}
		extshift := ""
		amount := ""
		if a.extShift != ExtShift(0) {
			switch a.extShift {
			default:
				extshift = "." + a.extShift.String()

			case lsl:
				extshift = "<<"
				amount = fmt.Sprintf("%d", a.amount)
				return reg + extshift + amount

			case lsr:
				extshift = ">>"
				amount = fmt.Sprintf("%d", a.amount)
				return reg + extshift + amount

			case asr:
				extshift = "->"
				amount = fmt.Sprintf("%d", a.amount)
				return reg + extshift + amount
			case ror:
				extshift = "@>"
				amount = fmt.Sprintf("%d", a.amount)
				return reg + extshift + amount
			}
			if a.amount != 0 {
				amount = fmt.Sprintf("<<%d", a.amount)
			}
		}
		return reg + extshift + amount

	case MemImmediate:
		off := ""
		base := ""
		regno := uint16(a.Base) & 31
		if regno == 31 {
			base = "(RSP)"
		} else {
			base = fmt.Sprintf("(R%d)", regno)
		}
		if a.imm != 0 && a.Mode != AddrPostReg {
			off = fmt.Sprintf("%d", a.imm)
		} else if a.Mode == AddrPostReg {
			postR := fmt.Sprintf("(R%d)", a.imm)
			return base + postR
		}
		return off + base

	case MemExtend:
		base := ""
		index := ""
		indexreg := ""
		regno := uint16(a.Base) & 31
		if regno == 31 {
			base = "(RSP)"
		} else {
			base = fmt.Sprintf("(R%d)", regno)
		}
		regno = uint16(a.Index) & 31
		if regno == 31 {
			indexreg = "ZR"
		} else {
			indexreg = fmt.Sprintf("R%d", regno)
		}

		if a.Extend == lsl {
			// Refer to ARM reference manual, for byte load/store(register), the index
			// shift amount must be 0, encoded in "S" as 0 if omitted, or as 1 if present.
			// a.Amount indicates the index shift amount, encoded in "S" field.
			// a.ShiftMustBeZero is set true indicates the index shift amount must be 0.
			// When a.ShiftMustBeZero is true, GNU syntax prints "[Xn, Xm lsl #0]" if "S"
			// equals to 1, or prints "[Xn, Xm]" if "S" equals to 0.
			if a.Amount != 0 && !a.ShiftMustBeZero {
				index = fmt.Sprintf("(%s<<%d)", indexreg, a.Amount)
			} else if a.ShiftMustBeZero && a.Amount == 1 {
				// When a.ShiftMustBeZero is ture, Go syntax prints "(Rm<<0)" if "a.Amount"
				// equals to 1.
				index = fmt.Sprintf("(%s<<0)", indexreg)
			} else {
				index = fmt.Sprintf("(%s)", indexreg)
			}
		} else {
			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())
			}
		}

		return base + index

	case Cond:
		switch arg.String() {
		case "CS":
			return "HS"
		case "CC":
			return "LO"
		}

	case Imm_clrex:
		return fmt.Sprintf("$%d", uint32(a))

	case Imm_dcps:
		return fmt.Sprintf("$%d", uint32(a))

	case Imm_option:
		return fmt.Sprintf("$%d", uint8(a))

	case Imm_hint:
		return fmt.Sprintf("$%d", uint8(a))

	case Imm_fp:
		var s, pre, numerator, denominator int16
		var result float64
		if a.s == 0 {
			s = 1
		} else {
			s = -1
		}
		pre = s * int16(16+a.pre)
		if a.exp > 0 {
			numerator = (pre << uint8(a.exp))
			denominator = 16
		} else {
			numerator = pre
			denominator = (16 << uint8(-1*a.exp))
		}
		result = float64(numerator) / float64(denominator)
		return strings.TrimRight(fmt.Sprintf("$%f", result), "0")

	case RegisterWithArrangement:
		result := a.r.String()
		arrange := a.a.String()
		c := []rune(arrange)
		switch len(c) {
		case 3:
			c[1], c[2] = c[2], c[1] // .8B -> .B8
		case 4:
			c[1], c[2], c[3] = c[3], c[1], c[2] // 16B -> B16
		}
		arrange = string(c)
		result += arrange
		if a.cnt > 0 {
			result = "[" + result
			for i := 1; i < int(a.cnt); i++ {
				cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
				result += ", " + cur.String() + arrange
			}
			result += "]"
		}
		return result

	case RegisterWithArrangementAndIndex:
		result := a.r.String()
		arrange := a.a.String()
		result += arrange
		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)
				result += ", " + cur.String() + arrange
			}
			result += "]"
		}
		return fmt.Sprintf("%s[%d]", result, a.index)

	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())
}