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