feat(asm): encode the arm64 Q-width FP load and store

FMOVQ routes through the MOV load/store machinery in the plain, post-index,
pre-index and static-symbol forms.  The Q width carries its size in the opc
field, so the store spelling is opc=10 and the access scales by sixteen;
both come from helpers now instead of the size exponent.  The static-symbol
form takes the toolchain's twelve-byte ADRP + ADD + access fallback with the
R_ADDRARM64 pair.  The register-to-register and immediate forms stay
rejected, matching the toolchain's own table.

Assisted-by: GLM 5.3 Flash
This commit is contained in:
petrbalvin committed 2026-10-07 02:36:24 +02:00
1 parent a6bd9c1ebe
commit daf7fad5b9
5 files changed
+161 -9

No files matched your search

+16 -1
View File
@@ -1518,11 +1518,26 @@ var a64LoadTable = map[string]a64LSType{
// a64StoreOpc returns the store opc for a given load type: integer and FP
// stores both encode opc=00 (the load's signedness bit sits in opc[1], which
// the store form clears; FP registers are selected by V, not opc).
// the store form clears; FP registers are selected by V, not opc). The one
// exception is the 128-bit Q width, whose store is the opc=10 spelling: with
// opc=00 the size field selects STR B instead (STR Qt is size=00, opc=10).
func a64StoreOpc(t a64LSType) int {
if t.size == 0 && t.V == 1 {
return 2
}
return 0
}
// a64LSScale returns the byte width an access's unsigned offset divides by.
// The Q width carries its size in opc (the size field stays 0), yet scales
// by 16 like any other 128-bit access, so the exponent alone does not answer.
func a64LSScale(t a64LSType) int64 {
if t.size == 0 && t.V == 1 {
return 16
}
return int64(1) << uint(t.size)
}
// arm64RegClass discriminates integer (R), floating-point (F) registers for
// the MOV pseudo-instruction.
type arm64RegClass int