feat(asm): encode the arm64 SVE gather loads and scatter stores
Assisted-by: GLM 5.3
This commit is contained in:
1 parent
6faf850793
commit
104bea036b
5 files changed
+1273
-2
No files matched your search
@@ -79,6 +79,20 @@ func arm64ExtStatement(mnem string, ops []*ast.Operand) (extops []arch.ExtOperan
|
||||
out = append(out, ext)
|
||||
continue
|
||||
}
|
||||
// The gather/scatter destination list, [Z13.B]: one scalable vector
|
||||
// in brackets, its arrangement part of the instruction's identity.
|
||||
if strings.HasPrefix(text, "[") && strings.HasSuffix(text, "]") {
|
||||
if ext, ok := arm64ExtVector(strings.Trim(text, "[]")); ok {
|
||||
out = append(out, ext)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// The gather/scatter memory operand: a parenthesised register pair,
|
||||
// an immediate-offset base or a lone vector base.
|
||||
if ext, ok := arm64ExtSveMem(text); ok {
|
||||
out = append(out, ext)
|
||||
continue
|
||||
}
|
||||
if ext, ok := arm64ExtVector(text); ok {
|
||||
out = append(out, ext)
|
||||
continue
|
||||
@@ -285,6 +299,122 @@ func arm64ExtSIMD(text string) (arch.ExtOperand, bool) {
|
||||
return arch.ExtOperand{Kind: arch.ExtVReg, Reg: reg}, true
|
||||
}
|
||||
|
||||
// arm64ExtSveMem parses the gather/scatter memory operand off a normalised
|
||||
// operand text: the parenthesised pair (R6)(R14), (Z23.D<<1)(R24) and
|
||||
// (Z4.S.UXTW)(R3), the immediate-offset base 6(Z7.S), and the lone vector
|
||||
// base (Z5.D) of the stores. The second parenthesis accepts the
|
||||
// stack-pointer spelling RSP; the ranges and the mode's own rules are left
|
||||
// to the encoding, whose diagnostics name them.
|
||||
func arm64ExtSveMem(text string) (arch.ExtOperand, bool) {
|
||||
// The immediate-offset spelling: digits straight before the parenthesis.
|
||||
if i := strings.IndexByte(text, '('); i > 0 && i == strings.LastIndexByte(text, '(') {
|
||||
disp, err := strconv.ParseUint(text[:i], 10, 32)
|
||||
if err == nil && strings.HasSuffix(text, ")") {
|
||||
op, ok := arm64ExtSveMemGroup(text[i+1 : len(text)-1])
|
||||
if !ok {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
if !op.BaseVec || op.Extend != 0 || op.Shift != 0 {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op.Imm = int64(disp)
|
||||
return op, true
|
||||
}
|
||||
}
|
||||
// The parenthesised forms: one group or two.
|
||||
rest, ok := strings.CutPrefix(text, "(")
|
||||
if !ok || !strings.HasSuffix(text, ")") {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
rest = rest[:len(rest)-1]
|
||||
first := rest
|
||||
op := arch.ExtOperand{Off: -1}
|
||||
if base, second, found := strings.Cut(rest, ")("); found {
|
||||
first = base
|
||||
off, ok := arm64ExtSveMemOffset(second)
|
||||
if !ok {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op = off
|
||||
}
|
||||
group, ok := arm64ExtSveMemGroup(first)
|
||||
if !ok {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
group.Off = op.Off
|
||||
group.Reg31 = op.Reg31
|
||||
return group, true
|
||||
}
|
||||
|
||||
// arm64ExtSveMemGroup parses one parenthesised memory register: R6, R6<<3,
|
||||
// Z23.D, Z23.D<<1, Z4.S.UXTW or Z7.D.SXTW. The general registers run
|
||||
// R0-R30 and the scalable vectors Z0-Z31 with an .S or .D element size and
|
||||
// an optional UXTW or SXTW extension; the ranges are left to the encoding.
|
||||
func arm64ExtSveMemGroup(text string) (arch.ExtOperand, bool) {
|
||||
op := arch.ExtOperand{Kind: arch.ExtSveMem, Off: -1}
|
||||
if base, shift, found := strings.Cut(text, "<<"); found {
|
||||
n, err := strconv.Atoi(shift)
|
||||
if err != nil || n < 0 {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op.Shift = n
|
||||
text = base
|
||||
}
|
||||
parts := strings.Split(text, ".")
|
||||
switch parts[0][0] {
|
||||
case 'R':
|
||||
reg, err := strconv.Atoi(parts[0][1:])
|
||||
if err != nil || len(parts) != 1 {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op.Reg = reg
|
||||
case 'Z':
|
||||
reg, err := strconv.Atoi(parts[0][1:])
|
||||
if err != nil || len(parts) < 2 || len(parts) > 3 {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
switch parts[1] {
|
||||
case "S":
|
||||
op.Arr = arch.ExtArrS
|
||||
case "D":
|
||||
op.Arr = arch.ExtArrD
|
||||
default:
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op.Reg = reg
|
||||
op.BaseVec = true
|
||||
if len(parts) == 3 {
|
||||
switch parts[2] {
|
||||
case "UXTW":
|
||||
op.Extend = 1
|
||||
case "SXTW":
|
||||
op.Extend = 2
|
||||
default:
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
}
|
||||
default:
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
return op, true
|
||||
}
|
||||
|
||||
// arm64ExtSveMemOffset parses the second parenthesis of a gather/scatter
|
||||
// memory operand: a plain R0-R30 or the stack-pointer spelling RSP.
|
||||
func arm64ExtSveMemOffset(text string) (arch.ExtOperand, bool) {
|
||||
if text == "RSP" {
|
||||
return arch.ExtOperand{Off: 31, Reg31: 2}, true
|
||||
}
|
||||
if len(text) < 2 || text[0] != 'R' {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
reg, err := strconv.Atoi(text[1:])
|
||||
if err != nil {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
return arch.ExtOperand{Off: reg}, true
|
||||
}
|
||||
|
||||
// arm64ExtRegDigits parses the digits and optional arrangement suffix of a
|
||||
// register spelling once the letter prefix is gone.
|
||||
func arm64ExtRegDigits(text string) (reg int, arr arch.ExtArrangement, ok bool) {
|
||||
|
||||
Reference in new issue
Block a user