fix(asm): enforce the arm64 VLD/VST post-index contract

Assisted-by: GLM 5.3
This commit is contained in:
petrbalvin committed 2026-10-07 13:49:49 +02:00
1 parent 7bc80ccb54
commit 2385bb7069
3 files changed
+83 -12

No files matched your search

+33 -1
View File
@@ -4978,11 +4978,22 @@ func encodeARM64VLDST(mnem string, post uint32, ops []*ast.Operand) ([]byte, err
if off != 0 && post == 0 {
return nil, fmt.Errorf("%s: offset %d not supported, plain and list accesses take a plain (Rn) operand", mnem, off)
}
// The toolchain's addressing contract for the structure forms (asm7.go's
// class ladder): an index register exists only as the post-index
// increment, so it is illegal without .P and takes neither an offset nor
// an extend nor a shift beside it.
idx := ops[memIdx].Addr.Index
if idx != "" && post == 0 {
return nil, fmt.Errorf("%s: illegal combination: the register index is a post-index, it needs the .P spelling", mnem)
}
if idx != "" && (ops[memIdx].Addr.Shift != "" || ops[memIdx].Addr.HasOff) {
return nil, fmt.Errorf("%s: invalid extended register op: the post-index register takes no offset, extend or shift", mnem)
}
// The post-index increment: 11111 for an immediate offset, else the
// spelled (Rn)(Rm) register.
rm := 31
if post != 0 {
if idx := ops[memIdx].Addr.Index; idx != "" {
if idx != "" {
if rm = arm64RegNum(idx); rm < 0 {
return nil, fmt.Errorf("%s: invalid post-index register %q", mnem, idx)
}
@@ -5000,6 +5011,14 @@ func encodeARM64VLDST(mnem string, post uint32, ops []*ast.Operand) ([]byte, err
if !ok {
return nil, fmt.Errorf("%s: invalid arrangement %q", mnem, vs[0].arr)
}
// The immediate post-increment transfers one element per register,
// not a whole register (VLD3R.P 6(R15), [V15.H4,V16.H4,V17.H4]).
// An unspelled offset (or a spelled zero, the same class) is the
// implicit by-size increment the Rm=11111 encoding carries; any
// other spelled value must match.
if post != 0 && idx == "" && off != 0 && off != int64(n)*(1<<uint(size)) {
return nil, fmt.Errorf("%s: invalid post-increment offset %d, want %d", mnem, off, n*(1<<uint(size)))
}
w := a64VLDNReplicate[n] | q<<30 | size<<10 | uint32(rn)<<5 | uint32(vs[0].reg)
if post != 0 {
w |= 1<<23 | uint32(rm)<<16
@@ -5024,6 +5043,19 @@ func encodeARM64VLDST(mnem string, post uint32, ops []*ast.Operand) ([]byte, err
return nil, fmt.Errorf("%s: invalid arrangement %q", mnem, vs[0].arr)
}
n := len(vs)
// The immediate post-increment moves the whole list: count times the
// register width (16 bytes in the Q forms, 8 otherwise). An unspelled
// offset (or a spelled zero) is the implicit by-size increment
// (Rm=11111); any other spelled value must match.
if post != 0 && idx == "" && off != 0 {
regBytes := 8
if q != 0 {
regBytes = 16
}
if off != int64(n)*int64(regBytes) {
return nil, fmt.Errorf("%s: invalid post-increment offset %d, want %d", mnem, off, n*regBytes)
}
}
base := a64VLD1Base[n]
if !load {
base = a64VST1Base[n]