feat(arch): add the amd64 extended-instruction layer with BF16 and VP2INTERSECT

Assisted-by: GLM 5.3 Flash
This commit is contained in:
petrbalvin committed 2026-10-07 00:07:58 +02:00
1 parent 2d803e38d8
commit 28bea95128
6 files changed
+803 -8

No files matched your search

+82 -1
View File
@@ -6,7 +6,8 @@
// 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.
// per architecture; the amd64 side of the layer lives in amd64_ext.go and
// 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
@@ -26,6 +27,13 @@ const (
ExtZReg ExtOperandKind = iota // scalable vector register Z0-Z31
ExtPReg // predicate register P0-P15
ExtImm // immediate
// The amd64 layer's register kinds.
ExtXMM // 128-bit vector register XMM0-XMM31
ExtYMM // 256-bit vector register YMM0-YMM31
ExtZMM // 512-bit vector register ZMM0-ZMM31
ExtKReg // opmask register K0-K7
ExtR32 // 32-bit general register EAX-R15D
ExtR64 // 64-bit general register RAX-R15
)
// String returns a short label for the kind.
@@ -37,6 +45,18 @@ func (k ExtOperandKind) String() string {
return "predicate register"
case ExtImm:
return "immediate"
case ExtXMM:
return "XMM register"
case ExtYMM:
return "YMM register"
case ExtZMM:
return "ZMM register"
case ExtKReg:
return "opmask register"
case ExtR32:
return "32-bit general register"
case ExtR64:
return "64-bit general register"
default:
return "operand"
}
@@ -225,6 +245,33 @@ const (
// multiply (immediate) class: MUL $-128, Z0.B computes Z0 = Z0 * -128.
// Operands: simm8, Zdn. No shift exists in this class.
ExtFormSignedImmediate
// The amd64 layer's operand shapes, sources first, destination last.
// The vector register class an entry takes comes from the encoding
// template (the L'L field names it), not from the form.
// ExtFormAmdVec3 is the EVEX non-destructive three-vector form:
// VCVTNE2PS2BF16 Z6, Z5, Z4. Operands: src1, src2, dest.
ExtFormAmdVec3
// ExtFormAmdVec2 is the two-vector form: VPOPCNTD Z1, Z2, VCOMISH X1, X2.
// Operands: src, dest.
ExtFormAmdVec2
// ExtFormAmdVec2Half is the two-vector form whose destination is the
// half-width companion of the source, equal at 128 bits: VCVTNEPS2BF16
// Y6, Z5. Operands: src, dest.
ExtFormAmdVec2Half
// ExtFormAmdMask2 is the form with an opmask destination and two vector
// sources: VP2INTERSECTD K0, Z2, Z1. Operands: src1, src2, dest.
ExtFormAmdMask2
// ExtFormAmdVecGprVec is the three-operand conversion with a
// general-register source: VCVTSI2SH X1, X2, EAX. Operands: src1, gpr,
// dest.
ExtFormAmdVecGprVec
// ExtFormAmdGprVec is the two-operand form with a general-register
// source and a vector destination: VMOVW X1, EAX and VCVTSH2SI EAX, X1.
// Operands: gpr, dest.
ExtFormAmdGprVec
// ExtFormAmdVecGpr is the two-operand form with a vector source and a
// general-register destination: VMOVW EAX, X1. Operands: src, dest.
ExtFormAmdVecGpr
)
// Arity returns the operand count the form takes.
@@ -234,6 +281,10 @@ func (f ExtForm) Arity() int {
return 3
case ExtFormImmediate, ExtFormSignedImmediate:
return 2
case ExtFormAmdVec3, ExtFormAmdMask2, ExtFormAmdVecGprVec:
return 3
case ExtFormAmdVec2, ExtFormAmdVec2Half, ExtFormAmdGprVec, ExtFormAmdVecGpr:
return 2
default:
return 0
}
@@ -250,6 +301,9 @@ func (f ExtForm) Kinds() []ExtOperandKind {
return []ExtOperandKind{ExtZReg, ExtPReg, ExtZReg}
case ExtFormImmediate, ExtFormSignedImmediate:
return []ExtOperandKind{ExtImm, ExtZReg}
// The amd64 forms return no kinds: the exact vector class depends on the
// entry's encoding template (its L'L field), which the form alone cannot
// name, and the encode paths diagnose the class themselves.
default:
return nil
}
@@ -266,6 +320,20 @@ func (f ExtForm) String() string {
return "unsigned immediate"
case ExtFormSignedImmediate:
return "signed immediate"
case ExtFormAmdVec3:
return "three vectors"
case ExtFormAmdVec2:
return "two vectors"
case ExtFormAmdVec2Half:
return "two vectors, half-width destination"
case ExtFormAmdMask2:
return "two vectors into an opmask"
case ExtFormAmdVecGprVec:
return "vector, general register, vector"
case ExtFormAmdGprVec:
return "general register, vector"
case ExtFormAmdVecGpr:
return "vector, general register"
default:
return "unknown form"
}
@@ -296,6 +364,14 @@ type ExtInstr struct {
Size ExtField // element-size field the arrangement fills
Feature ExtFeature // sve or sve2
Ref string // the ARM ARM entry the encoding comes from
// Bytes is the amd64 encoding template: the EVEX prefix, opcode and
// ModR/M byte of one form, with every register-derived bit zero. The
// vector length and the general-register width an entry encodes are read
// back out of it at encode time.
Bytes []byte
// Wig records that the entry ignores the W bit in its general-register
// position, so both 32-bit and 64-bit registers encode.
Wig bool
}
// Encode assembles the operands into the 4 little-endian bytes of the
@@ -316,6 +392,9 @@ func (in ExtInstr) Encode(ops []ExtOperand) ([]byte, error) {
return in.encodeImmediate(ops)
case ExtFormSignedImmediate:
return in.encodeSignedImmediate(ops)
case ExtFormAmdVec3, ExtFormAmdVec2, ExtFormAmdVec2Half, ExtFormAmdMask2,
ExtFormAmdVecGprVec, ExtFormAmdGprVec, ExtFormAmdVecGpr:
return in.encodeAmd64(ops)
default:
return nil, fmt.Errorf("%s: unknown form %d", in.Name, in.Form)
}
@@ -616,6 +695,8 @@ var arm64Extensions = []ExtInstr{
// it simply offers no instruction where none is registered.
func Extensions(a Arch) []ExtInstr {
switch a {
case AMD64:
return amd64Extensions
case ARM64:
return arm64Extensions
default: