625 lines
25 KiB
Go
625 lines
25 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// This file carries the extended-instruction layer: instructions the Go
|
|
// toolchain does not know at all, described as data and validated against
|
|
// golden vectors from the Arm Architecture Reference Manual rather than
|
|
// against the toolchain. It sits beside the generated tables, never inside
|
|
// them: arch/arm64_gen.go stays untouched, and Extensions returns the layer
|
|
// per architecture so a later amd64 table attaches through the same door.
|
|
//
|
|
// The first entry is the arm64 SVE and SVE2 integer add/subtract/multiply
|
|
// family (twenty-three forms over four word shapes). The encodings are
|
|
// transcribed from the manual and cross-checked against the GNU assembler's
|
|
// and LLVM's published encodings; the golden vectors in arm64_ext_test.go pin
|
|
// the bytes.
|
|
|
|
package arch
|
|
|
|
import "fmt"
|
|
|
|
// ExtOperandKind classifies one operand of an extended instruction.
|
|
type ExtOperandKind uint8
|
|
|
|
// Operand kinds.
|
|
const (
|
|
ExtZReg ExtOperandKind = iota // scalable vector register Z0-Z31
|
|
ExtPReg // predicate register P0-P15
|
|
ExtImm // immediate
|
|
)
|
|
|
|
// String returns a short label for the kind.
|
|
func (k ExtOperandKind) String() string {
|
|
switch k {
|
|
case ExtZReg:
|
|
return "scalable vector register"
|
|
case ExtPReg:
|
|
return "predicate register"
|
|
case ExtImm:
|
|
return "immediate"
|
|
default:
|
|
return "operand"
|
|
}
|
|
}
|
|
|
|
// ExtArrangement is the element-size suffix a scalable vector operand
|
|
// carries: .B, .H, .S, .D or .Q. ExtArrNone means the operand is written
|
|
// bare, which the SVE forms in this layer reject.
|
|
type ExtArrangement uint8
|
|
|
|
// Arrangements, widest last.
|
|
const (
|
|
ExtArrNone ExtArrangement = iota
|
|
ExtArrB // 8-bit elements
|
|
ExtArrH // 16-bit elements
|
|
ExtArrS // 32-bit elements
|
|
ExtArrD // 64-bit elements
|
|
ExtArrQ // 128-bit elements
|
|
)
|
|
|
|
// String returns the assembler suffix, with the leading dot.
|
|
func (a ExtArrangement) String() string {
|
|
switch a {
|
|
case ExtArrB:
|
|
return ".B"
|
|
case ExtArrH:
|
|
return ".H"
|
|
case ExtArrS:
|
|
return ".S"
|
|
case ExtArrD:
|
|
return ".D"
|
|
case ExtArrQ:
|
|
return ".Q"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// Width returns the byte width of one element under the arrangement.
|
|
func (a ExtArrangement) Width() int {
|
|
switch a {
|
|
case ExtArrB:
|
|
return 1
|
|
case ExtArrH:
|
|
return 2
|
|
case ExtArrS:
|
|
return 4
|
|
case ExtArrD:
|
|
return 8
|
|
case ExtArrQ:
|
|
return 16
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// sizeBits maps the arrangement onto the two-bit size field the integer SVE
|
|
// classes carry at bits 23..22: 00=B, 01=H, 10=S, 11=D. ok is false for the
|
|
// arrangements no such class accepts (.Q and the bare spelling).
|
|
func (a ExtArrangement) sizeBits() (uint32, bool) {
|
|
switch a {
|
|
case ExtArrB, ExtArrH, ExtArrS, ExtArrD:
|
|
return uint32(a) - 1, true
|
|
default:
|
|
return 0, false
|
|
}
|
|
}
|
|
|
|
// ExtQualifier is the predicate qualifier spelled after the slash.
|
|
type ExtQualifier uint8
|
|
|
|
// Predicate qualifiers.
|
|
const (
|
|
ExtQualNone ExtQualifier = iota // bare Pn (non-predicating position)
|
|
ExtQualMerging // /M, inactive lanes keep the destination
|
|
ExtQualZeroing // /Z, inactive lanes become zero
|
|
)
|
|
|
|
// String returns the assembler spelling, with the leading slash.
|
|
func (q ExtQualifier) String() string {
|
|
switch q {
|
|
case ExtQualMerging:
|
|
return "/M"
|
|
case ExtQualZeroing:
|
|
return "/Z"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// ExtOperand is one operand of an extended instruction, already resolved to
|
|
// its pieces: a register with its arrangement and qualifier, or an immediate
|
|
// with its optional left shift. The assembler's future hook constructs these
|
|
// from the parsed statement; Encode consumes them.
|
|
type ExtOperand struct {
|
|
Kind ExtOperandKind
|
|
Reg int // register number (Z: 0..31, P: 0..15)
|
|
Arr ExtArrangement // element-size suffix; ExtArrNone when bare
|
|
Qual ExtQualifier // predicate qualifier; ExtQualNone elsewhere
|
|
Imm int64 // immediate value (ExtImm only)
|
|
// Shift carries the LSL amount an immediate form shifts the constant by
|
|
// before use (0 or 8 in the SVE add/subtract immediate class). HasShift
|
|
// separates a spelled shift (validated as written) from an unshifted
|
|
// operand (the encoder may derive the sh bit from the value).
|
|
Shift int
|
|
HasShift bool
|
|
}
|
|
|
|
// ExtVector builds a scalable vector operand, ADD Z1.S style.
|
|
func ExtVector(reg int, arr ExtArrangement) ExtOperand {
|
|
return ExtOperand{Kind: ExtZReg, Reg: reg, Arr: arr}
|
|
}
|
|
|
|
// ExtPredicate builds a predicate operand with its qualifier, P0/M style.
|
|
func ExtPredicate(reg int, qual ExtQualifier) ExtOperand {
|
|
return ExtOperand{Kind: ExtPReg, Reg: reg, Qual: qual}
|
|
}
|
|
|
|
// ExtImmediate builds an unshifted immediate operand.
|
|
func ExtImmediate(v int64) ExtOperand {
|
|
return ExtOperand{Kind: ExtImm, Imm: v}
|
|
}
|
|
|
|
// ExtShiftedImmediate builds an immediate operand with a spelled LSL amount.
|
|
func ExtShiftedImmediate(v int64, shift int) ExtOperand {
|
|
return ExtOperand{Kind: ExtImm, Imm: v, Shift: shift, HasShift: true}
|
|
}
|
|
|
|
// ExtField is one named field of the 32-bit encoding word: a bit offset from
|
|
// the least significant end and the field's width.
|
|
type ExtField struct {
|
|
Off uint8
|
|
Width uint8
|
|
}
|
|
|
|
// extMask returns the field's bits as a mask.
|
|
func extMask(f ExtField) uint32 {
|
|
return ^uint32(0) >> (32 - f.Width)
|
|
}
|
|
|
|
// extSet ORs v into the field of word.
|
|
func extSet(word uint32, f ExtField, v uint32) uint32 {
|
|
return word | (v&extMask(f))<<f.Off
|
|
}
|
|
|
|
// The fields the SVE integer classes use. The 5-bit register fields are
|
|
// named after their role in the three-vector class; the predicated class
|
|
// reuses extFieldRn for its Zm operand and extFieldPg for the governing
|
|
// predicate, which that class narrows to three bits (P0-P7).
|
|
var (
|
|
extFieldRd = ExtField{0, 5} // destination (Zd or Zdn)
|
|
extFieldRn = ExtField{5, 5} // first source (Zn, or Zm in the predicated class)
|
|
extFieldRm = ExtField{16, 5} // second source (Zm in the three-vector class)
|
|
extFieldPg = ExtField{10, 3} // governing predicate P0-P7 (predicated class)
|
|
extFieldImm8 = ExtField{5, 8} // the immediate, bits 12..5
|
|
extFieldSh = ExtField{13, 1} // the shift flag: 1 means LSL #8
|
|
extSizeBHSD = ExtField{22, 2} // element-size field of every class here, bits 23..22
|
|
)
|
|
|
|
// ExtForm enumerates the operand shapes the extension layer defines, in Plan
|
|
// 9 order (sources first, destination last). A destructive SVE operand is
|
|
// written once, in destination position: the encoding carries no second copy.
|
|
type ExtForm uint8
|
|
|
|
// Operand shapes.
|
|
const (
|
|
// ExtFormVectors is the unpredicated three-vector form, the SVE integer
|
|
// add/subtract (unpredicated) class: ADD Z0.S, Z1.S, Z2.S computes
|
|
// Z0 = Z1 + Z2. Operands: Zn, Zm, Zd.
|
|
ExtFormVectors ExtForm = iota
|
|
// ExtFormPredicated is the governed destructive form, the SVE integer
|
|
// add/subtract vectors (predicated) class: ADD Z1.S, P0/M, Z0.S computes
|
|
// Z0 = Z0 + Z1 for the active lanes. Operands: Zm, Pg/M, Zdn. The
|
|
// governing predicate is a 3-bit field, so only P0-P7 encode here, and
|
|
// the class takes the merging qualifier alone: a zeroing form would need
|
|
// a MOVPRFX expansion, which one data word cannot carry.
|
|
ExtFormPredicated
|
|
// ExtFormImmediate is the add/subtract immediate form, the SVE integer
|
|
// add/subtract (immediate) class: ADD $255, Z0.S computes
|
|
// Z0 = Z0 + 255. Operands: imm{, LSL #8}, Zdn. The constant is an
|
|
// unsigned imm8, optionally shifted left by 8 bits; a bare multiple of
|
|
// 256 (up to 65280) derives the shift, the spelling the GNU assembler
|
|
// canonicalises too. .B takes no shift.
|
|
ExtFormImmediate
|
|
// ExtFormSignedImmediate is the signed immediate form of the SVE integer
|
|
// multiply (immediate) class: MUL $-128, Z0.B computes Z0 = Z0 * -128.
|
|
// Operands: simm8, Zdn. No shift exists in this class.
|
|
ExtFormSignedImmediate
|
|
)
|
|
|
|
// Arity returns the operand count the form takes.
|
|
func (f ExtForm) Arity() int {
|
|
switch f {
|
|
case ExtFormVectors, ExtFormPredicated:
|
|
return 3
|
|
case ExtFormImmediate, ExtFormSignedImmediate:
|
|
return 2
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// Kinds returns the operand kind each position of the form wants, in the
|
|
// order the operands arrive. The registry uses the list to pick the most
|
|
// specific rejection when every matching form refuses an operand list.
|
|
func (f ExtForm) Kinds() []ExtOperandKind {
|
|
switch f {
|
|
case ExtFormVectors:
|
|
return []ExtOperandKind{ExtZReg, ExtZReg, ExtZReg}
|
|
case ExtFormPredicated:
|
|
return []ExtOperandKind{ExtZReg, ExtPReg, ExtZReg}
|
|
case ExtFormImmediate, ExtFormSignedImmediate:
|
|
return []ExtOperandKind{ExtImm, ExtZReg}
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// String returns a short label for the form, for diagnostics.
|
|
func (f ExtForm) String() string {
|
|
switch f {
|
|
case ExtFormVectors:
|
|
return "unpredicated vectors"
|
|
case ExtFormPredicated:
|
|
return "predicated (merging)"
|
|
case ExtFormImmediate:
|
|
return "unsigned immediate"
|
|
case ExtFormSignedImmediate:
|
|
return "signed immediate"
|
|
default:
|
|
return "unknown form"
|
|
}
|
|
}
|
|
|
|
// ExtFeature names the architecture feature an extended instruction belongs
|
|
// to. The field is metadata: the assembler offers every instruction it
|
|
// registers, and a feature check is the caller's decision, not the encoder's.
|
|
type ExtFeature string
|
|
|
|
// The features the arm64 layer covers.
|
|
const (
|
|
ExtFeatureSVE ExtFeature = "sve"
|
|
ExtFeatureSVE2 ExtFeature = "sve2"
|
|
)
|
|
|
|
// ExtInstr is one extended instruction: the metadata a lookup needs and the
|
|
// encoding as data. Word holds the fixed bits of the 32-bit encoding with
|
|
// every operand field and the size field zero; the form says which fields the
|
|
// operands fill; the size field receives the arrangement's bits at encode
|
|
// time. Ref names the manual entry the encoding is transcribed from, the
|
|
// golden source in place of a toolchain oracle.
|
|
type ExtInstr struct {
|
|
Name string // upper-case mnemonic
|
|
Summary string // one line of hover documentation
|
|
Word uint32 // fixed encoding bits, operand fields zero
|
|
Form ExtForm // operand shape
|
|
Size ExtField // element-size field the arrangement fills
|
|
Feature ExtFeature // sve or sve2
|
|
Ref string // the ARM ARM entry the encoding comes from
|
|
}
|
|
|
|
// Encode assembles the operands into the 4 little-endian bytes of the
|
|
// instruction word. The operand kinds, register ranges, arrangements and
|
|
// immediate ranges are validated against the form; an operand the class
|
|
// cannot carry is an error, never a silent mis-encoding.
|
|
func (in ExtInstr) Encode(ops []ExtOperand) ([]byte, error) {
|
|
if len(ops) != in.Form.Arity() {
|
|
return nil, fmt.Errorf("%s: the %s form takes %d operands, got %d",
|
|
in.Name, in.Form, in.Form.Arity(), len(ops))
|
|
}
|
|
switch in.Form {
|
|
case ExtFormVectors:
|
|
return in.encodeVectors(ops)
|
|
case ExtFormPredicated:
|
|
return in.encodePredicated(ops)
|
|
case ExtFormImmediate:
|
|
return in.encodeImmediate(ops)
|
|
case ExtFormSignedImmediate:
|
|
return in.encodeSignedImmediate(ops)
|
|
default:
|
|
return nil, fmt.Errorf("%s: unknown form %d", in.Name, in.Form)
|
|
}
|
|
}
|
|
|
|
// encodeVectors fills the unpredicated three-vector form: Zn, Zm, Zd, all
|
|
// under one required arrangement.
|
|
func (in ExtInstr) encodeVectors(ops []ExtOperand) ([]byte, error) {
|
|
for i, op := range ops {
|
|
if op.Kind != ExtZReg {
|
|
return nil, fmt.Errorf("%s: operand %d wants a scalable vector register, got %s",
|
|
in.Name, i+1, op.Kind)
|
|
}
|
|
if op.Reg < 0 || op.Reg > 31 {
|
|
return nil, fmt.Errorf("%s: operand %d is Z%d, outside Z0-Z31", in.Name, i+1, op.Reg)
|
|
}
|
|
}
|
|
arr, err := in.sharedArrangement(ops)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
size, ok := arr.sizeBits()
|
|
if !ok {
|
|
return nil, fmt.Errorf("%s: arrangement %s has no size encoding in this class", in.Name, arr)
|
|
}
|
|
word := in.Word
|
|
word = extSet(word, extFieldRn, uint32(ops[0].Reg))
|
|
word = extSet(word, extFieldRm, uint32(ops[1].Reg))
|
|
word = extSet(word, extFieldRd, uint32(ops[2].Reg))
|
|
word = extSet(word, in.Size, size)
|
|
return extWordLE(word), nil
|
|
}
|
|
|
|
// encodePredicated fills the governed destructive form: Zm, Pg/M, Zdn. The
|
|
// predicate is a 3-bit field, the merging qualifier alone, and carries no
|
|
// arrangement suffix in this class.
|
|
func (in ExtInstr) encodePredicated(ops []ExtOperand) ([]byte, error) {
|
|
zm, pg, zdn := ops[0], ops[1], ops[2]
|
|
if zm.Kind != ExtZReg {
|
|
return nil, fmt.Errorf("%s: operand 1 wants a scalable vector register, got %s",
|
|
in.Name, zm.Kind)
|
|
}
|
|
if zm.Reg < 0 || zm.Reg > 31 {
|
|
return nil, fmt.Errorf("%s: operand 1 is Z%d, outside Z0-Z31", in.Name, zm.Reg)
|
|
}
|
|
if pg.Kind != ExtPReg {
|
|
return nil, fmt.Errorf("%s: operand 2 wants a predicate register, got %s",
|
|
in.Name, pg.Kind)
|
|
}
|
|
if pg.Reg < 0 || pg.Reg > 7 {
|
|
return nil, fmt.Errorf("%s: operand 2 is P%d, outside P0-P7 in this class", in.Name, pg.Reg)
|
|
}
|
|
if pg.Qual != ExtQualMerging {
|
|
return nil, fmt.Errorf("%s: operand 2 wants the merging qualifier /M, got %q",
|
|
in.Name, pg.Qual)
|
|
}
|
|
if pg.Arr != ExtArrNone {
|
|
return nil, fmt.Errorf("%s: the governing predicate carries no arrangement suffix, got %s",
|
|
in.Name, pg.Arr)
|
|
}
|
|
if zdn.Kind != ExtZReg {
|
|
return nil, fmt.Errorf("%s: operand 3 wants a scalable vector register, got %s",
|
|
in.Name, zdn.Kind)
|
|
}
|
|
if zdn.Reg < 0 || zdn.Reg > 31 {
|
|
return nil, fmt.Errorf("%s: operand 3 is Z%d, outside Z0-Z31", in.Name, zdn.Reg)
|
|
}
|
|
if zm.Arr != zdn.Arr {
|
|
return nil, fmt.Errorf("%s: operands 1 and 3 carry arrangements %s and %s, they must match",
|
|
in.Name, zm.Arr, zdn.Arr)
|
|
}
|
|
size, ok := zdn.Arr.sizeBits()
|
|
if !ok {
|
|
return nil, fmt.Errorf("%s: arrangement %s has no size encoding in this class", in.Name, zdn.Arr)
|
|
}
|
|
word := in.Word
|
|
word = extSet(word, extFieldRn, uint32(zm.Reg))
|
|
word = extSet(word, extFieldPg, uint32(pg.Reg))
|
|
word = extSet(word, extFieldRd, uint32(zdn.Reg))
|
|
word = extSet(word, in.Size, size)
|
|
return extWordLE(word), nil
|
|
}
|
|
|
|
// encodeImmediate fills the add/subtract immediate form: imm{, LSL #8}, Zdn.
|
|
// The class encodes an unsigned imm8 with one shift bit, so a bare multiple
|
|
// of 256 derives the shift the way the GNU assembler canonicalises it.
|
|
func (in ExtInstr) encodeImmediate(ops []ExtOperand) ([]byte, error) {
|
|
imm, zdn := ops[0], ops[1]
|
|
imm8, sh, err := in.addSubImmediate(imm, zdn.Arr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
word := in.Word
|
|
word = extSet(word, extFieldImm8, uint32(imm8))
|
|
if sh != 0 {
|
|
word = extSet(word, extFieldSh, 1)
|
|
}
|
|
word, err = in.setDestAndSize(word, zdn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return extWordLE(word), nil
|
|
}
|
|
|
|
// encodeSignedImmediate fills the multiply immediate form: simm8, Zdn, with
|
|
// no shift bit in the class.
|
|
func (in ExtInstr) encodeSignedImmediate(ops []ExtOperand) ([]byte, error) {
|
|
imm, zdn := ops[0], ops[1]
|
|
if imm.Kind != ExtImm {
|
|
return nil, fmt.Errorf("%s: operand 1 wants an immediate, got %s", in.Name, imm.Kind)
|
|
}
|
|
if imm.HasShift {
|
|
return nil, fmt.Errorf("%s: the signed immediate class takes no shift", in.Name)
|
|
}
|
|
if imm.Imm < -128 || imm.Imm > 127 {
|
|
return nil, fmt.Errorf("%s: immediate %d is outside the signed 8-bit range -128..127",
|
|
in.Name, imm.Imm)
|
|
}
|
|
word := in.Word
|
|
word = extSet(word, extFieldImm8, uint32(imm.Imm))
|
|
word, err := in.setDestAndSize(word, zdn)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return extWordLE(word), nil
|
|
}
|
|
|
|
// addSubImmediate resolves the immediate operand of the add/subtract
|
|
// immediate class into its imm8 and shift bit: a spelled shift is validated
|
|
// as written, a bare multiple of 256 (on .H, .S or .D) derives one.
|
|
func (in ExtInstr) addSubImmediate(op ExtOperand, arr ExtArrangement) (imm8, sh int, err error) {
|
|
if op.Kind != ExtImm {
|
|
return 0, 0, fmt.Errorf("%s: operand 1 wants an immediate, got %s", in.Name, op.Kind)
|
|
}
|
|
switch {
|
|
case op.HasShift:
|
|
if op.Shift != 0 && op.Shift != 8 {
|
|
return 0, 0, fmt.Errorf("%s: the shift amount must be 0 or 8, got %d", in.Name, op.Shift)
|
|
}
|
|
if arr == ExtArrB && op.Shift != 0 {
|
|
return 0, 0, fmt.Errorf("%s: arrangement .B takes no shift", in.Name)
|
|
}
|
|
if op.Imm < 0 || op.Imm > 255 {
|
|
return 0, 0, fmt.Errorf("%s: immediate %d is outside the unsigned 8-bit range 0..255",
|
|
in.Name, op.Imm)
|
|
}
|
|
return int(op.Imm), op.Shift, nil
|
|
case op.Imm >= 0 && op.Imm <= 255:
|
|
return int(op.Imm), 0, nil
|
|
case arr != ExtArrB && op.Imm >= 256 && op.Imm <= 255<<8 && op.Imm%256 == 0:
|
|
// A bare multiple of 256 rides the shift bit, 65280 = 255<<8 included.
|
|
return int(op.Imm / 256), 8, nil
|
|
default:
|
|
return 0, 0, fmt.Errorf("%s: immediate %d is not an unsigned imm8%s, nor a multiple of 256 the shift bit can carry",
|
|
in.Name, op.Imm, arr.shiftNote())
|
|
}
|
|
}
|
|
|
|
// shiftNote describes where a shifted constant is expressible, for the
|
|
// immediate range error.
|
|
func (arr ExtArrangement) shiftNote() string {
|
|
if arr == ExtArrB {
|
|
return " (and .B takes no shifted constant)"
|
|
}
|
|
return " (a multiple of 256 up to 65280 shifts)"
|
|
}
|
|
|
|
// setDestAndSize fills the destructive destination register and the size
|
|
// field from the arrangement the vector carries.
|
|
func (in ExtInstr) setDestAndSize(word uint32, zdn ExtOperand) (uint32, error) {
|
|
if zdn.Kind != ExtZReg {
|
|
return 0, fmt.Errorf("%s: operand 2 wants a scalable vector register, got %s",
|
|
in.Name, zdn.Kind)
|
|
}
|
|
if zdn.Reg < 0 || zdn.Reg > 31 {
|
|
return 0, fmt.Errorf("%s: operand 2 is Z%d, outside Z0-Z31", in.Name, zdn.Reg)
|
|
}
|
|
size, ok := zdn.Arr.sizeBits()
|
|
if !ok {
|
|
return 0, fmt.Errorf("%s: arrangement %s has no size encoding in this class", in.Name, zdn.Arr)
|
|
}
|
|
word = extSet(word, extFieldRd, uint32(zdn.Reg))
|
|
word = extSet(word, in.Size, size)
|
|
return word, nil
|
|
}
|
|
|
|
// sharedArrangement returns the one arrangement all vector operands carry, or
|
|
// an error when any operand is bare or they disagree.
|
|
func (in ExtInstr) sharedArrangement(ops []ExtOperand) (ExtArrangement, error) {
|
|
arr := ops[0].Arr
|
|
for i, op := range ops {
|
|
if op.Arr == ExtArrNone {
|
|
return 0, fmt.Errorf("%s: operand %d carries no arrangement suffix", in.Name, i+1)
|
|
}
|
|
if op.Arr != arr {
|
|
return 0, fmt.Errorf("%s: operand %d carries arrangement %s, want %s",
|
|
in.Name, i+1, op.Arr, arr)
|
|
}
|
|
}
|
|
return arr, nil
|
|
}
|
|
|
|
// extWordLE returns a 32-bit encoding word as 4 little-endian bytes.
|
|
func extWordLE(w uint32) []byte {
|
|
return []byte{byte(w), byte(w >> 8), byte(w >> 16), byte(w >> 24)}
|
|
}
|
|
|
|
// --- the arm64 SVE/SVE2 table ------------------------------------------------
|
|
|
|
// arm64Extensions is the extended instruction layer of arm64: the SVE and
|
|
// SVE2 integer add/subtract/multiply family. The Go toolchain knows none of
|
|
// these; the encodings are transcribed from the ARM Architecture Reference
|
|
// Manual (DDI 0487J, Part C, Chapter C8, the alphabetical list of SVE
|
|
// instructions) and cross-checked against the GNU assembler's and LLVM's
|
|
// published encodings.
|
|
var arm64Extensions = []ExtInstr{
|
|
// Unpredicated three-vector forms: ADD Z0.S, Z1.S, Z2.S.
|
|
{Name: "ADD", Summary: "Add scalable vector elements, unpredicated",
|
|
Word: 0x04200000, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: ADD (vectors, unpredicated)"},
|
|
{Name: "SUB", Summary: "Subtract scalable vector elements, unpredicated",
|
|
Word: 0x04200400, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SUB (vectors, unpredicated)"},
|
|
{Name: "SQADD", Summary: "Add signed saturating scalable vector elements, unpredicated",
|
|
Word: 0x04201000, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SQADD (vectors, unpredicated)"},
|
|
{Name: "UQADD", Summary: "Add unsigned saturating scalable vector elements, unpredicated",
|
|
Word: 0x04201400, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: UQADD (vectors, unpredicated)"},
|
|
{Name: "SQSUB", Summary: "Subtract signed saturating scalable vector elements, unpredicated",
|
|
Word: 0x04201800, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SQSUB (vectors, unpredicated)"},
|
|
{Name: "UQSUB", Summary: "Subtract unsigned saturating scalable vector elements, unpredicated",
|
|
Word: 0x04201c00, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: UQSUB (vectors, unpredicated)"},
|
|
{Name: "MUL", Summary: "Multiply scalable vector elements, unpredicated",
|
|
Word: 0x04206000, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: MUL (vectors, unpredicated)"},
|
|
{Name: "SMULH", Summary: "Multiply signed scalable vector elements, keeping the high half, unpredicated",
|
|
Word: 0x04206800, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SMULH (vectors, unpredicated)"},
|
|
{Name: "UMULH", Summary: "Multiply unsigned scalable vector elements, keeping the high half, unpredicated",
|
|
Word: 0x04206c00, Form: ExtFormVectors, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: UMULH (vectors, unpredicated)"},
|
|
|
|
// Governed destructive forms, merging: ADD Z1.S, P0/M, Z0.S.
|
|
{Name: "ADD", Summary: "Add scalable vector elements under a governing predicate, merging",
|
|
Word: 0x04000000, Form: ExtFormPredicated, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: ADD (vectors, predicated)"},
|
|
{Name: "SUB", Summary: "Subtract scalable vector elements under a governing predicate, merging",
|
|
Word: 0x04010000, Form: ExtFormPredicated, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SUB (vectors, predicated)"},
|
|
{Name: "SUBR", Summary: "Reverse-subtract scalable vector elements under a governing predicate, merging",
|
|
Word: 0x04030000, Form: ExtFormPredicated, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SUBR (vectors, predicated)"},
|
|
{Name: "MUL", Summary: "Multiply scalable vector elements under a governing predicate, merging",
|
|
Word: 0x04100000, Form: ExtFormPredicated, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: MUL (vectors, predicated)"},
|
|
{Name: "SMULH", Summary: "Multiply signed scalable vector elements, keeping the high half, under a governing predicate, merging",
|
|
Word: 0x04120000, Form: ExtFormPredicated, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SMULH (vectors, predicated)"},
|
|
{Name: "UMULH", Summary: "Multiply unsigned scalable vector elements, keeping the high half, under a governing predicate, merging",
|
|
Word: 0x04130000, Form: ExtFormPredicated, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: UMULH (vectors, predicated)"},
|
|
|
|
// Immediate forms: ADD $255, Z0.S.
|
|
{Name: "ADD", Summary: "Add an unsigned immediate to scalable vector elements",
|
|
Word: 0x2520c000, Form: ExtFormImmediate, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: ADD (vectors, immediate)"},
|
|
{Name: "SUB", Summary: "Subtract an unsigned immediate from scalable vector elements",
|
|
Word: 0x2521c000, Form: ExtFormImmediate, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SUB (vectors, immediate)"},
|
|
{Name: "SUBR", Summary: "Subtract scalable vector elements from an unsigned immediate",
|
|
Word: 0x2523c000, Form: ExtFormImmediate, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SUBR (vectors, immediate)"},
|
|
{Name: "SQADD", Summary: "Add a signed saturating unsigned immediate to scalable vector elements",
|
|
Word: 0x2524c000, Form: ExtFormImmediate, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SQADD (vectors, immediate)"},
|
|
{Name: "UQADD", Summary: "Add an unsigned saturating immediate to scalable vector elements",
|
|
Word: 0x2525c000, Form: ExtFormImmediate, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: UQADD (vectors, immediate)"},
|
|
{Name: "SQSUB", Summary: "Subtract an unsigned immediate from scalable vector elements with signed saturation",
|
|
Word: 0x2526c000, Form: ExtFormImmediate, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: SQSUB (vectors, immediate)"},
|
|
{Name: "UQSUB", Summary: "Subtract an unsigned immediate from scalable vector elements with unsigned saturation",
|
|
Word: 0x2527c000, Form: ExtFormImmediate, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: UQSUB (vectors, immediate)"},
|
|
|
|
// The signed immediate of the multiply class: MUL $-128, Z0.B.
|
|
{Name: "MUL", Summary: "Multiply scalable vector elements by a signed immediate",
|
|
Word: 0x2530c000, Form: ExtFormSignedImmediate, Size: extSizeBHSD, Feature: ExtFeatureSVE,
|
|
Ref: "ARM DDI 0487J, C8.2 SVE instruction descriptions: MUL (vectors, immediate)"},
|
|
}
|
|
|
|
// Extensions returns the extended-instruction layer registered for a, outside
|
|
// the generated tables. An architecture whose extended layer is not built
|
|
// yet returns nothing: the mechanism is ordinary code, not a build tag, and
|
|
// it simply offers no instruction where none is registered.
|
|
func Extensions(a Arch) []ExtInstr {
|
|
switch a {
|
|
case ARM64:
|
|
return arm64Extensions
|
|
default:
|
|
return nil
|
|
}
|
|
}
|