fix(asm): enforce the arm64 VLD/VST post-index contract
Assisted-by: GLM 5.3
This commit is contained in:
1 parent
7bc80ccb54
commit
2385bb7069
3 files changed
+83
-12
No files matched your search
+33
-1
@@ -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]
|
||||
|
||||
Reference in new issue
Block a user