feat(arch): the SVE predicate family in the extended layer
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
83052ab466
commit
8231302bca
5 files changed
+1451
-42
No files matched your search
+143
-1
@@ -119,7 +119,7 @@ func TestArm64AssembleExtensionRefusals(t *testing.T) {
|
||||
{"ADD Z1.S, P9/M, Z0.S", "outside P0-P7"},
|
||||
{"ADD $300, Z0.S", "immediate 300"},
|
||||
{"ADD $255<<8, Z0.S", "not an immediate the layer can read"},
|
||||
{"ADD Z1.S, P0/M, R0", "not an extended-layer operand"},
|
||||
{"ADD Z1.S, P0/M, R0", "wants a scalable vector register"},
|
||||
{"ADD Z1.S, P0/B, Z0.S", "not an extended-layer operand"},
|
||||
{"MUL $200, Z0.B", "outside the signed 8-bit range"},
|
||||
{"ADD Z1.S, LSL #8, Z0.S", "LSL belongs straight after an immediate"},
|
||||
@@ -132,6 +132,148 @@ func TestArm64AssembleExtensionRefusals(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionPredicateGolden drives the predicate family
|
||||
// through the full assembler: corpus spellings in, corpus words out. The
|
||||
// want words are the same arm64sveenc.s lines the arch-level golden test
|
||||
// pins; these prove the text-to-bytes path parses the dot and slash
|
||||
// qualifiers, the general registers and the counter spelling the statements
|
||||
// write.
|
||||
func TestArm64AssembleExtensionPredicateGolden(t *testing.T) {
|
||||
tests := []struct {
|
||||
stmt string
|
||||
want uint32
|
||||
}{
|
||||
// The logical operations, .B alone, the governing predicate with the
|
||||
// zeroing qualifier in its dot spelling.
|
||||
{"PAND P4.B, P2.B, P1.Z, P14.B", 0x2504444e},
|
||||
{"PANDS P4.B, P2.B, P1.Z, P14.B", 0x2544444e},
|
||||
{"PBIC P4.B, P2.B, P1.Z, P14.B", 0x2504445e},
|
||||
{"PEOR P4.B, P2.B, P1.Z, P14.B", 0x2504464e},
|
||||
{"PNAND P4.B, P2.B, P1.Z, P14.B", 0x2584465e},
|
||||
{"PORR P4.B, P2.B, P1.Z, P14.B", 0x2584444e},
|
||||
// The slash qualifier spells the same operand the dot spelling does.
|
||||
{"PAND P4.B, P2.B, P1/Z, P14.B", 0x2504444e},
|
||||
// The select and the breaks.
|
||||
{"PSEL P4.B, P2.B, P1, P14.B", 0x2504465e},
|
||||
{"PBRKA P5.B, P9.Z, P2.B", 0x251064a2},
|
||||
{"PBRKAS P5.B, P9.Z, P4.B", 0x255064a4},
|
||||
{"PBRKN P4.B, P2.B, P1.Z, P4.B", 0x25184444},
|
||||
{"PBRKPA P4.B, P2.B, P1.Z, P14.B", 0x2504c44e},
|
||||
// The permutations carry the arrangement into the size field.
|
||||
{"PTRN1 P5.D, P4.D, P2.D", 0x05e55082},
|
||||
{"PUZP2 P5.D, P4.D, P2.D", 0x05e54c82},
|
||||
{"PZIP1 P5.H, P4.H, P2.H", 0x05654082},
|
||||
// The singles and the first-fault group.
|
||||
{"PPFALSE P13.B", 0x2518e40d},
|
||||
{"PPFIRST P5.B, P9, P5.B", 0x2558c125},
|
||||
{"PPNEXT P5.D, P4, P5.D", 0x25d9c485},
|
||||
{"PPTEST P14.B, P0", 0x2550c1c0},
|
||||
{"PPUNPKHI P14.B, P0.H", 0x053141c0},
|
||||
{"PRDFFR P13.B", 0x2519f00d},
|
||||
{"PRDFFR P14.Z, P0.B", 0x2518f1c0},
|
||||
{"PRDFFRS P14.Z, P0.B", 0x2558f1c0},
|
||||
{"PWRFFR P13.B", 0x252891a0},
|
||||
{"PREV P14.S, P13.S", 0x05b441cd},
|
||||
{"SETFFR", 0x252c9000},
|
||||
// The while compares: general registers in, a sized predicate out.
|
||||
{"PWHILEGE R2, R10, P10.H", 0x2562114a},
|
||||
{"PWHILELT R2, R10, P10.H", 0x2562154a},
|
||||
{"PWHILELS R2, R10, P10.B", 0x25221d5a},
|
||||
{"PWHILERW R2, R10, P10.H", 0x2562315a},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
words := assembleArm64Words(t, arm64ExtProbeHead+"\t"+tt.stmt+"\n\tRET\n")
|
||||
if len(words) != 2 {
|
||||
t.Fatalf("%s: got %d words, want the statement and RET", tt.stmt, len(words))
|
||||
}
|
||||
if words[0] != tt.want {
|
||||
t.Errorf("%s:\n got %08x\n want %08x", tt.stmt, words[0], tt.want)
|
||||
}
|
||||
if words[1] != 0xd65f03c0 {
|
||||
t.Errorf("%s: RET encoded %08x", tt.stmt, words[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionPredicateRefusals pins the diagnostics the
|
||||
// predicate statements get from the layer.
|
||||
func TestArm64AssembleExtensionPredicateRefusals(t *testing.T) {
|
||||
tests := []struct {
|
||||
stmt string
|
||||
want string
|
||||
}{
|
||||
{"PAND P4.B, P2.B, P1.M, P14.B", "zeroing qualifier"},
|
||||
{"PAND P4.B, P2.B, P9.Z, P14.B", "outside P0-P7"},
|
||||
{"PAND P8.B, P2.B, P1.Z, P14.B", "outside P0-P7"},
|
||||
{"PAND P4.S, P2.B, P1.Z, P14.B", "want .B"},
|
||||
{"PBRKN P4.B, P2.B, P1.Z, P9.B", "same register Pdm"},
|
||||
{"PBRKAS P5.B, P9.M, P4.B", "zeroing qualifier"},
|
||||
{"PSEL P4.B, P2.B, P1.Z, P14.B", "takes no qualifier"},
|
||||
{"PTRN1 P5.D, P4.S, P2.D", "want .D"},
|
||||
{"PPFALSE P13.S", "want .B"},
|
||||
{"PPTRUE P6.S", "predicate-as-counter register"},
|
||||
{"PPTRUE PN6.S", "outside PN8-PN15"},
|
||||
{"PWHILELT R2, R31, P10.H", "outside R0-R30"},
|
||||
{"PWHILELT R2, R10, P10.Q", "no size encoding"},
|
||||
{"SETFFR P0.B", "takes 0 operands"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := assembleArm64SrcError(t, arm64ExtProbeHead+"\t"+tt.stmt+"\n\tRET\n")
|
||||
if !strings.Contains(got, tt.want) {
|
||||
t.Errorf("%s: error %q does not name %q", tt.stmt, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionPredicateLeavesScalarsAlone pins the non-
|
||||
// invasion promise across the new operand kinds: general-register
|
||||
// statements whose mnemonics the layer also carries for predicates keep
|
||||
// their scalar behaviour whenever no vector, predicate or counter operand
|
||||
// appears.
|
||||
func TestArm64AssembleExtensionPredicateLeavesScalarsAlone(t *testing.T) {
|
||||
tests := []struct {
|
||||
stmt string
|
||||
want uint32
|
||||
}{
|
||||
{"ADD R0, R1, R2", 0x8b000022},
|
||||
{"SUB R0, R1, R2", 0xcb000022},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
words := assembleArm64Words(t, arm64ExtProbeHead+"\t"+tt.stmt+"\n\tRET\n")
|
||||
if len(words) != 2 {
|
||||
t.Fatalf("%s: got %d words, want the statement and RET", tt.stmt, len(words))
|
||||
}
|
||||
if words[0] != tt.want {
|
||||
t.Errorf("%s:\n got %08x\n want %08x", tt.stmt, words[0], tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionPredicateLabelOffsets proves pass 1 and pass 2
|
||||
// agree on a function mixing the predicate family with the vector family:
|
||||
// PWHILELT (4 bytes) and SETFFR (4 bytes) shift the label by exactly the
|
||||
// words pass 2 lays down.
|
||||
func TestArm64AssembleExtensionPredicateLabelOffsets(t *testing.T) {
|
||||
src := arm64ExtProbeHead + `
|
||||
PWHILELT R2, R10, P10.H
|
||||
loop:
|
||||
SETFFR
|
||||
B loop
|
||||
PPFALSE P13.B
|
||||
RET
|
||||
`
|
||||
words := assembleArm64Words(t, src)
|
||||
want := []uint32{0x2562154a, 0x252c9000, 0x17ffffff, 0x2518e40d, 0xd65f03c0}
|
||||
if len(words) != len(want) {
|
||||
t.Fatalf("got %d words, want %d", len(words), len(want))
|
||||
}
|
||||
for i := range want {
|
||||
if words[i] != want[i] {
|
||||
t.Errorf("word %d: got %08x, want %08x", i, words[i], want[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionLabelOffsets proves pass 1 and pass 2 agree on a
|
||||
// function that mixes the layer with ordinary statements: the label after an
|
||||
// SVE instruction lands on the 4 bytes the encoder laid down, and the branch
|
||||
|
||||
Reference in new issue
Block a user