feat(arch): the SVE2.1 last-active vector and compare families

Assisted-by: GLM 5.3 Flash
This commit is contained in:
petrbalvin committed 2026-10-07 20:35:41 +02:00
1 parent 12a5cfff52
commit bd85f8838d
4 files changed
+147 -9

No files matched your search

+134 -5
View File
@@ -701,6 +701,18 @@ const (
// Zm.H, Zn.H, Pg/M, Zda.H. Fields: Zm at bits 16..20, Zn in the
// first-source slot, Pg narrow, Zda in the destination slot.
ExtFormMulPred
// ExtFormCompare is the SVE2 compare to a predicate destination,
// ZCMPEQ Z0.H, Z2.H, P0.Z, P14.H: the comparison writes the zeroing
// predicate P0-P7 spelled with its zeroing qualifier. Operands: Zm.T,
// Zn.T, Pg/Z, Pd.T under one shared arrangement, which feeds the size
// field. Fields: Zm at bits 16..20, Zn in the first-source slot, Pg
// narrow, Pd in the four-bit destination slot.
ExtFormCompare
// ExtFormCompareWide is the wide compare, ZCMPEQ Z0.D, Z12.S, P0.Z,
// P14.S: the compared magnitudes ride a double-width vector locked to
// .D while the compared data shares one narrower arrangement. Operands:
// Zm.D, Zn.T, Pg/Z, Pd.T.
ExtFormCompareWide
// ExtFormLongMul is the SVE2 BFloat16 lengthened multiply,
// ZBFMLALB Z7.H, Z6.H, Z23.S: two halfword vectors multiply into a
// word accumulator, the wide source locked to .S. Operands: Za.H,
@@ -725,7 +737,8 @@ func (f ExtForm) Arity() int {
ExtFormZUnary, ExtFormZGov, ExtFormVectorsZm, ExtFormZImmediateSource:
return 3
case ExtFormPredicateLogical, ExtFormPredicateSelect, ExtFormPredicateLogicalDest,
ExtFormZPredicatedSource, ExtFormZSelect, ExtFormThreeSource, ExtFormMulPred:
ExtFormZPredicatedSource, ExtFormZSelect, ExtFormThreeSource, ExtFormMulPred,
ExtFormCompare, ExtFormCompareWide:
return 4
case ExtFormImmediate, ExtFormSignedImmediate, ExtFormPredicateFFRRead,
ExtFormPredicateMove, ExtFormPredicateUnpack, ExtFormPredicateTest,
@@ -827,7 +840,7 @@ func (f ExtForm) Kinds() []ExtOperandKind {
return []ExtOperandKind{ExtZReg, ExtZReg, ExtZReg}
case ExtFormConvert:
return []ExtOperandKind{ExtZReg, ExtPReg, ExtZReg}
case ExtFormThreeSource, ExtFormMulPred:
case ExtFormThreeSource, ExtFormMulPred, ExtFormCompare, ExtFormCompareWide:
return []ExtOperandKind{ExtZReg, ExtZReg, ExtPReg, ExtZReg}
case ExtFormQuadReduce:
return []ExtOperandKind{ExtZReg, ExtPReg, ExtVReg}
@@ -967,6 +980,10 @@ func (f ExtForm) String() string {
return "multiply-accumulate"
case ExtFormLongMul:
return "lengthened multiply"
case ExtFormCompare:
return "compare to a predicate"
case ExtFormCompareWide:
return "wide compare to a predicate"
case ExtFormNone:
return "no operands"
default:
@@ -1233,6 +1250,10 @@ func (in ExtInstr) Encode(ops []ExtOperand) ([]byte, error) {
return in.encodeMulPred(ops)
case ExtFormLongMul:
return in.encodeLongMul(ops)
case ExtFormCompare:
return in.encodeCompare(ops)
case ExtFormCompareWide:
return in.encodeCompare(ops)
case ExtFormNone:
if len(ops) != 0 {
return nil, fmt.Errorf("%s: the %s form takes no operands, got %d",
@@ -1893,9 +1914,9 @@ func (in ExtInstr) encodeZPredicatedSource(ops []ExtOperand) ([]byte, error) {
if err := in.zVector(ops[3], 4); err != nil {
return nil, err
}
if pg.Qual != ExtQualMerging {
return nil, fmt.Errorf("%s: operand 3 wants the merging qualifier, got %q",
in.Name, pg.Qual)
if want := in.PgQual; pg.Qual != want {
return nil, fmt.Errorf("%s: operand 3 wants the %s qualifier, got %q",
in.Name, want.String(), pg.Qual)
}
if ops[3].Reg != zdn.Reg || ops[3].Arr != zdn.Arr {
return nil, fmt.Errorf("%s: operands 2 and 4 are the same register Zdn, got Z%d and Z%d",
@@ -2832,6 +2853,62 @@ func (in ExtInstr) encodeMulPred(ops []ExtOperand) ([]byte, error) {
// encodeLongMul fills the SVE2 BFloat16 lengthened multiply: Za.H, Zn.H,
// Zm.S, the two halfword vectors under the row's Arr and the wide source
// one step above it.
// encodeCompare fills the SVE2 compare forms, the shared-arrangement and
// the wide shape alike: Zm, Zn, Pg/Z, Pd. The comparison writes the
// zeroing predicate P0-P7; under the wide shape the magnitudes ride the
// double-width vector locked to .D. Fields: Zm at bits 16..20, Zn in the
// first-source slot, Pg narrow, Pd in the four-bit destination slot.
func (in ExtInstr) encodeCompare(ops []ExtOperand) ([]byte, error) {
zm, zn, pg, pd := ops[0], ops[1], ops[2], ops[3]
if err := in.zVector(zm, 1); err != nil {
return nil, err
}
if in.Form == ExtFormCompareWide {
if zm.Arr != ExtArrD {
return nil, fmt.Errorf("%s: operand 1 carries arrangement %s, want .D", in.Name, zm.Arr)
}
}
if err := in.zVector(zn, 2); err != nil {
return nil, err
}
if in.Form == ExtFormCompare && zn.Arr != zm.Arr {
return nil, fmt.Errorf("%s: operands 1 and 2 carry arrangements %s and %s, they must match", in.Name, zm.Arr, zn.Arr)
}
if in.Form == ExtFormCompareWide {
if zn.Arr == ExtArrD {
return nil, fmt.Errorf("%s: operand 2 carries arrangement .D, want .B, .H or .S", in.Name)
}
}
if err := in.predicateOperand(pg, 3, 0, 7, ExtArrNone); err != nil {
return nil, err
}
if pg.Qual != ExtQualZeroing {
return nil, fmt.Errorf("%s: operand 3 wants the zeroing qualifier, got %q", in.Name, pg.Qual)
}
if pd.Kind != ExtPReg {
return nil, fmt.Errorf("%s: operand 4 wants a predicate register, got %s", in.Name, pd.Kind)
}
if pd.Reg < 0 || pd.Reg > 15 {
return nil, fmt.Errorf("%s: operand 4 is P%d, outside P0-P15", in.Name, pd.Reg)
}
if in.Form == ExtFormCompare && pd.Arr != zn.Arr {
return nil, fmt.Errorf("%s: operand 4 carries arrangement %s, want %s", in.Name, pd.Arr, zn.Arr)
}
size, err := in.zSize(zn.Arr)
if err != nil {
return nil, err
}
word := in.Word
word = extSet(word, extFieldRm, uint32(zm.Reg))
word = extSet(word, extFieldRn, uint32(zn.Reg))
word = extSet(word, extFieldPgN, uint32(pg.Reg))
word = extSet(word, extFieldPd, uint32(pd.Reg))
if size != 0 {
word = extSet(word, in.Size, size)
}
return extWordLE(word), nil
}
func (in ExtInstr) encodeLongMul(ops []ExtOperand) ([]byte, error) {
za, zn, zm := ops[0], ops[1], ops[2]
if err := in.zVector(za, 1); err != nil {
@@ -3668,6 +3745,58 @@ var arm64Extensions = []ExtInstr{
{Name: "ZBFSCALE", Summary: "Scale BFloat16 halfwords by a power of two, merging",
Word: 0x65098000, Form: ExtFormZPredicatedSource, Arr: ExtArrH, PgQual: ExtQualMerging, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZBFSCALE; inst_gen.go + arm64sveenc.s"},
// --- the SVE2.1 last-active and compare families --------------------------
//
// The conditionally-extract-last-active-element vector shape and the
// compares to a predicate destination, in their shared-arrangement and
// wide spellings. The register-destination shapes of CLASTA and
// CLASTB, and the immediate compares, stay unwired. Provenance as
// above: the toolchain encoding table and its generated corpus, both
// produced from Arm's official ISA description, and the golden test
// pins every corpus line of the covered classes.
{Name: "ZCLASTA", Summary: "Conditionally extract the last active element, vector to vector",
Word: 0x05288000, Form: ExtFormZPredicatedSource, Size: extSizeBHSD, PgQual: ExtQualNone, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCLASTA; inst_gen.go + arm64sveenc.s"},
{Name: "ZCLASTB", Summary: "Conditionally extract the last active element from the bottom, vector to vector",
Word: 0x05298000, Form: ExtFormZPredicatedSource, Size: extSizeBHSD, PgQual: ExtQualNone, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCLASTB; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPEQ", Summary: "Compare equal, writing a zeroing predicate",
Word: 0x2400a000, Form: ExtFormCompare, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPEQ; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPEQ", Summary: "Compare equal against wide magnitudes, writing a zeroing predicate",
Word: 0x24002000, Form: ExtFormCompareWide, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPEQ; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPGE", Summary: "Compare greater or equal signed, writing a zeroing predicate",
Word: 0x24008000, Form: ExtFormCompare, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPGE; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPGE", Summary: "Compare greater or equal signed against wide magnitudes, writing a zeroing predicate",
Word: 0x24004000, Form: ExtFormCompareWide, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPGE; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPGT", Summary: "Compare greater signed, writing a zeroing predicate",
Word: 0x24008010, Form: ExtFormCompare, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPGT; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPGT", Summary: "Compare greater signed against wide magnitudes, writing a zeroing predicate",
Word: 0x24004010, Form: ExtFormCompareWide, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPGT; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPHI", Summary: "Compare higher unsigned, writing a zeroing predicate",
Word: 0x24000010, Form: ExtFormCompare, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPHI; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPHI", Summary: "Compare higher unsigned against wide magnitudes, writing a zeroing predicate",
Word: 0x2400c010, Form: ExtFormCompareWide, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPHI; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPHS", Summary: "Compare higher or same unsigned, writing a zeroing predicate",
Word: 0x24000000, Form: ExtFormCompare, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPHS; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPHS", Summary: "Compare higher or same unsigned against wide magnitudes, writing a zeroing predicate",
Word: 0x2400c000, Form: ExtFormCompareWide, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPHS; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPNE", Summary: "Compare not equal, writing a zeroing predicate",
Word: 0x2400a010, Form: ExtFormCompare, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPNE; inst_gen.go + arm64sveenc.s"},
{Name: "ZCMPNE", Summary: "Compare not equal against wide magnitudes, writing a zeroing predicate",
Word: 0x24002010, Form: ExtFormCompareWide, Size: extSizeBHSD, Feature: ExtFeatureSVE2,
Ref: "ARM DDI 0487J SVE2: ZCMPNE; inst_gen.go + arm64sveenc.s"},
// --- the SVE multiple-structure loads and stores --------------------------
//
// The two-, three- and four-register list loads and stores over the
+2 -1
View File
@@ -311,7 +311,8 @@ func TestArm64ExtTableIntegrity(t *testing.T) {
ExtFormPredicateBreak, ExtFormPredicateBreakZero, ExtFormPredicatePermute,
ExtFormPredicateFirst, ExtFormPredicateNext, ExtFormPredicateOne,
ExtFormPredicateFFRRead, ExtFormPredicateMove, ExtFormPredicateUnpack,
ExtFormPredicateTest, ExtFormWhile, ExtFormPredicateCounter, ExtFormZUnary:
ExtFormPredicateTest, ExtFormWhile, ExtFormPredicateCounter, ExtFormZUnary,
ExtFormCompare, ExtFormCompareWide:
destMask = 0xf
}
roundOne := in.Form == ExtFormVectors || in.Form == ExtFormPredicated ||
+1 -1
View File
@@ -876,7 +876,7 @@ func TestArm64AssembleExtensionStage4Refusals(t *testing.T) {
{"ZADDHNB Z22.D, Z10.D, Z8.H", "want .S"},
{"ZADDHNB Z22.Q, Z10.Q, Z8.D", "want .H, .S or .D"},
{"ZADDHNB Z22.S, Z10.S, Z8", "carries no arrangement suffix"},
{"ZADDP Z15.B, Z0.B, P3.Z, Z0.B", "merging qualifier"},
{"ZADDP Z15.B, Z0.B, P3.Z, Z0.B", "/M qualifier"},
{"ZADDPT Z7.S, Z6.S, Z23.S", "want .D"},
{"ZADDQV Z25.S, P9, V5.S4", "outside P0-P7"},
{"ZADDQV Z25.S, P3/M, V5.S4", "takes no qualifier"},
+10 -2
View File
@@ -338,6 +338,14 @@ func TestExtensionNamesARM64(t *testing.T) {
"ZBFMLSLT",
"ZBFMMLA",
"ZBFSCALE",
"ZCLASTA",
"ZCLASTB",
"ZCMPEQ",
"ZCMPGE",
"ZCMPGT",
"ZCMPHI",
"ZCMPHS",
"ZCMPNE",
"ZLD2B",
"ZLD2D",
"ZLD2H",
@@ -480,7 +488,7 @@ func TestExtensionNamesARM64(t *testing.T) {
if strings.Join(got, ",") != strings.Join(want, ",") {
t.Errorf("ExtensionNames(ARM64) = %v, want %v", got, want)
}
if n := len(arch.Extensions(arch.ARM64)); n != 483 {
t.Errorf("the family registers %d instructions, want 483", n)
if n := len(arch.Extensions(arch.ARM64)); n != 497 {
t.Errorf("the family registers %d instructions, want 497", n)
}
}