feat(asm): encode the arm64 SVE2 crypto, counter and reduction families
Assisted-by: GLM 5.3
This commit is contained in:
1 parent
dac0a5b51b
commit
6faf850793
5 files changed
+1211
-16
No files matched your search
+54
-13
@@ -15,7 +15,11 @@
|
||||
// classes, and for the predicate family Pm.B, Pn.B, Pg/Z (or Pg.Z), Pd.B
|
||||
// for the logical operations, Pn.B, Pg.Z, Pd.B for the breaks, Pm.T, Pn.T,
|
||||
// Pd.T for the permutations, Rm, Rn, Pd.T for the while compares, PN8-PN15
|
||||
// for the counter destinations, and the bare SETFFR.
|
||||
// for the counter destinations, and the bare SETFFR. Stage three adds the
|
||||
// crypto family (Zn.T, Zd.T, Zd.T read-back and the in-place Zd.T, Zd.T),
|
||||
// the predicate counters (Pn.T, Pg, Rd; Pn.T, ZR; Rd, Pn.T, Rd; ZR and R
|
||||
// terminators) and the reductions (Zn.T, Pg, Vd over the SIMD register
|
||||
// V0-V31, with ZR and RSP accepted where the classes take them).
|
||||
|
||||
package asm
|
||||
|
||||
@@ -45,7 +49,7 @@ func arm64ExtStatement(mnem string, ops []*ast.Operand) (extops []arch.ExtOperan
|
||||
if _, ok := LookupExtension(arch.ARM64, mnem); !ok {
|
||||
return nil, false, nil
|
||||
}
|
||||
if !arm64ExtPinned(ops) {
|
||||
if !arm64ExtPinned(mnem, ops) {
|
||||
return nil, false, nil
|
||||
}
|
||||
out := make([]arch.ExtOperand, 0, len(ops))
|
||||
@@ -87,6 +91,18 @@ func arm64ExtStatement(mnem string, ops []*ast.Operand) (extops []arch.ExtOperan
|
||||
out = append(out, ext)
|
||||
continue
|
||||
}
|
||||
if text == "ZR" {
|
||||
out = append(out, arch.ExtZeroRegister())
|
||||
continue
|
||||
}
|
||||
if text == "RSP" {
|
||||
out = append(out, arch.ExtStackPointer())
|
||||
continue
|
||||
}
|
||||
if ext, ok := arm64ExtSIMD(text); ok {
|
||||
out = append(out, ext)
|
||||
continue
|
||||
}
|
||||
if ext, ok := arm64ExtGeneral(text); ok {
|
||||
out = append(out, ext)
|
||||
continue
|
||||
@@ -96,18 +112,27 @@ func arm64ExtStatement(mnem string, ops []*ast.Operand) (extops []arch.ExtOperan
|
||||
return out, true, nil
|
||||
}
|
||||
|
||||
// arm64ExtPinned reports whether the statement belongs to the layer: any
|
||||
// operand is a scalable vector, predicate or predicate-as-counter register,
|
||||
// the shapes only the extension layer reads, or the statement carries no
|
||||
// operands at all and the mnemonic's zero-operand forms claim it. The test
|
||||
// is deliberately loose about the suffixes: P0/B is not a spelling the
|
||||
// layer takes, but the P of it makes the statement the layer's, and the
|
||||
// conversion then diagnoses the operand precisely instead of leaving it to
|
||||
// a scalar path that would report an unrelated register error.
|
||||
func arm64ExtPinned(ops []*ast.Operand) bool {
|
||||
// arm64ExtPinned reports whether the statement belongs to the layer. A
|
||||
// mnemonic the extension layer registers on its own, one the generated
|
||||
// arm64 table does not know, owns every one of its statements: no scalar
|
||||
// path could mean it instead, and the layer's diagnostics replace the
|
||||
// unsupported-instruction complaint. A mnemonic both tables carry (the
|
||||
// SVE aliases of ADD, SUB and MUL) keeps the operand-shape test: any
|
||||
// operand is a scalable vector, predicate or predicate-as-counter
|
||||
// register, the shapes only the extension layer reads, or the statement
|
||||
// carries no operands at all and the mnemonic's zero-operand forms claim
|
||||
// it. The shape test is deliberately loose about the suffixes: P0/B is
|
||||
// not a spelling the layer takes, but the P of it makes the statement the
|
||||
// layer's, and the conversion then diagnoses the operand precisely
|
||||
// instead of leaving it to a scalar path that would report an unrelated
|
||||
// register error.
|
||||
func arm64ExtPinned(mnem string, ops []*ast.Operand) bool {
|
||||
if len(ops) == 0 {
|
||||
return true
|
||||
}
|
||||
if _, shared := a64InstrTable[mnem]; !shared {
|
||||
return true
|
||||
}
|
||||
for _, op := range ops {
|
||||
if op.Kind == ast.OpImmediate {
|
||||
continue
|
||||
@@ -230,8 +255,9 @@ func arm64ExtCounter(text string) (arch.ExtOperand, bool) {
|
||||
}
|
||||
|
||||
// arm64ExtGeneral parses a general register operand: R0..R30, the plain
|
||||
// spelling the while-compare forms take. The register range is left to the
|
||||
// encoding, whose diagnostics name it.
|
||||
// spelling the while-compare forms take, beside the ZR and RSP spellings of
|
||||
// the thirty-first slot the conversion above reads. The register range is
|
||||
// left to the encoding, whose diagnostics name it.
|
||||
func arm64ExtGeneral(text string) (arch.ExtOperand, bool) {
|
||||
rest, ok := strings.CutPrefix(text, "R")
|
||||
if !ok {
|
||||
@@ -244,6 +270,21 @@ func arm64ExtGeneral(text string) (arch.ExtOperand, bool) {
|
||||
return arch.ExtOperand{Kind: arch.ExtGReg, Reg: reg}, true
|
||||
}
|
||||
|
||||
// arm64ExtSIMD parses a 128-bit SIMD register operand: V0..V31, written
|
||||
// bare, the scalar destination the reductions and the crypto read-back
|
||||
// forms take. The register range is left to the encoding.
|
||||
func arm64ExtSIMD(text string) (arch.ExtOperand, bool) {
|
||||
rest, ok := strings.CutPrefix(text, "V")
|
||||
if !ok {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
reg, arr, ok := arm64ExtRegDigits(rest)
|
||||
if !ok || arr != arch.ExtArrNone {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
return arch.ExtOperand{Kind: arch.ExtVReg, Reg: 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