feat(arch): the SVE2.1 pairwise and quadword-reduction families

Assisted-by: GLM 5.3 Flash
This commit is contained in:
petrbalvin committed 2026-10-07 20:35:41 +02:00
1 parent 31ab584eee
commit b93fccc075
5 files changed
+212 -22

No files matched your search

+22 -4
View File
@@ -286,17 +286,35 @@ func arm64ExtGeneral(text string) (arch.ExtOperand, bool) {
// 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.
// forms take, or with the counted quadword suffix of the SVE2.1 QV class,
// V5.S4 reading four 32-bit lanes (the spellings .B16, .H8, .S4 and .D2;
// no other suffix parses). 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 {
arr := arch.ExtArrNone
for _, q := range []struct {
suffix string
arr arch.ExtArrangement
}{
{"B16", arch.ExtArrB},
{"H8", arch.ExtArrH},
{"S4", arch.ExtArrS},
{"D2", arch.ExtArrD},
} {
if s := "." + q.suffix; strings.HasSuffix(rest, s) {
arr = q.arr
rest = rest[:len(rest)-len(s)]
break
}
}
reg, bare, ok := arm64ExtRegDigits(rest)
if !ok || bare != arch.ExtArrNone {
return arch.ExtOperand{}, false
}
return arch.ExtOperand{Kind: arch.ExtVReg, Reg: reg}, true
return arch.ExtOperand{Kind: arch.ExtVReg, Reg: reg, Arr: arr}, true
}
// arm64ExtSveMem parses the gather/scatter memory operand off a normalised
+29 -2
View File
@@ -763,6 +763,26 @@ func TestArm64AssembleExtensionStage4Golden(t *testing.T) {
{"ZSUBHNT Z22.S, Z10.S, Z8.H", 0x45b67548},
{"ZADDHNB Z8.H, Z10.H, Z11.B", 0x4568614b},
{"ZSUBHNT Z26.D, Z4.D, Z13.S", 0x45fa748d},
// The pairwise and quadword-reduction classes: corpus lines plus a
// width extension each.
{"ZADDP Z15.B, Z0.B, P3.M, Z0.B", 0x4411ade0},
{"ZADDP Z9.S, Z2.S, P5.M, Z2.S", 0x4491b522},
{"ZADDPT Z23.D, Z13.D, P1.M, Z13.D", 0x04c406ed},
{"ZADDPT Z7.D, Z6.D, Z23.D", 0x04e708d7},
{"ZADDQV Z25.S, P3, V5.S4", 0x04852f25},
{"ZADDQV Z9.D, P1, V7.D2", 0x04c52527},
{"ZANDQV Z25.S, P3, V5.S4", 0x049e2f25},
{"ZEORQV Z25.S, P3, V5.S4", 0x049d2f25},
{"ZORQV Z25.S, P3, V5.S4", 0x049c2f25},
{"ZSMAXQV Z25.S, P3, V5.S4", 0x048c2f25},
{"ZSMINQV Z25.S, P3, V5.S4", 0x048e2f25},
{"ZUMAXQV Z25.S, P3, V5.S4", 0x048d2f25},
{"ZUMINQV Z25.S, P3, V5.S4", 0x048f2f25},
{"ZFADDQV Z25.S, P3, V5.S4", 0x6490af25},
{"ZFMAXNMQV Z25.S, P3, V5.S4", 0x6494af25},
{"ZFMAXQV Z25.S, P3, V5.S4", 0x6496af25},
{"ZFMINNMQV Z25.S, P3, V5.S4", 0x6495af25},
{"ZFMINQV Z25.S, P3, V5.S4", 0x6497af25},
}
for _, tt := range tests {
words := assembleArm64Words(t, arm64ExtProbeHead+"\t"+tt.stmt+"\n\tRET\n")
@@ -779,8 +799,9 @@ func TestArm64AssembleExtensionStage4Golden(t *testing.T) {
}
// TestArm64AssembleExtensionStage4Refusals pins the diagnostics the
// narrowing statements get from the layer: the arrangement pair the single
// size field over-determines.
// narrowing, pairwise and quadword-reduction statements get from the layer:
// the arrangement pair the single size field over-determines, the locked
// pairwise top arrangement and the accumulator's bare predicate.
func TestArm64AssembleExtensionStage4Refusals(t *testing.T) {
tests := []struct {
stmt string
@@ -792,6 +813,12 @@ 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"},
{"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"},
{"ZADDQV Z25.S, P3, V5", "no quadword suffix"},
{"ZADDQV Z25.S, P3, V5.D2", "carries arrangement .D, want .S"},
}
for _, tt := range tests {
got := assembleArm64SrcError(t, arm64ExtProbeHead+"\t"+tt.stmt+"\n\tRET\n")
+19 -3
View File
@@ -273,7 +273,8 @@ func TestExtensionNamesARM64(t *testing.T) {
"ZZIP2",
"ZZIPQ1",
"ZZIPQ2",
// The stage-four families: the SVE2.1 narrowing two-to-one set.
// The stage-four families: the SVE2.1 narrowing two-to-one set, the
// pairwise forms and the quadword reductions.
"ZADDHNB",
"ZADDHNT",
"ZRADDHNB",
@@ -282,6 +283,21 @@ func TestExtensionNamesARM64(t *testing.T) {
"ZRSUBHNT",
"ZSUBHNB",
"ZSUBHNT",
"ZADDP",
"ZADDPT",
"ZADDQV",
"ZANDQV",
"ZEORQV",
"ZFADDQV",
"ZFMAXNMQV",
"ZFMAXQV",
"ZFMINNMQV",
"ZFMINQV",
"ZORQV",
"ZSMAXQV",
"ZSMINQV",
"ZUMAXQV",
"ZUMINQV",
// The stage-three families: the SVE2 crypto group, the predicate
// counters and loop terminators with the 32-bit while compares, and
// the reductions into a SIMD register.
@@ -394,7 +410,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 != 389 {
t.Errorf("the family registers %d instructions, want 389", n)
if n := len(arch.Extensions(arch.ARM64)); n != 405 {
t.Errorf("the family registers %d instructions, want 405", n)
}
}