Skip to content

target-arm: AArch32 Neon integer data processing and loads and stores - #346

Merged
tamnd merged 2 commits into
mainfrom
m7-a32-neon
Oct 15, 2026
Merged

tamnd merged 2 commits into
mainfrom
m7-a32-neon

Conversation

@tamnd

@tamnd tamnd commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Part of #8.

The first Neon slice for AArch32: the integer data-processing instructions, the loads and stores, and VMOV and VDUP between core registers and scalars. It covers A32 and T32.

  • neon-dp.decode and neon-ls.decode are generated as for QEMU. T32 encodings are rewritten to their A32 form before decoding, as in translate.c.
  • The integer ops include:
    • three registers of the same length, and three of different lengths
    • two registers and a shift, including the narrowing and long forms
    • two registers and a scalar
    • the two-register miscellaneous group without the FP ops
    • VEXT, VTBL/VTBX, VDUP (scalar), VSWP, VTRN/VUZP/VZIP
    • the modified immediates
  • They run on the A64 vector helper through a new a32_neon helper, which maps D registers onto the Q registers. FPSCR.QC is set on saturation. Pair ops write Dm and then Dd, as QEMU does, so VTRN, VUZP and VZIP with d == m match.
  • VLDn/VSTn cover all forms: multiple structures, single lane and all lanes, with writeback by size or by register. Alignment checks follow QEMU's finalize_memop in user mode, so a hint is checked and the default alignment is not.
  • VMOV between core registers and scalars, and VDUP from a core register.

Not included: the FP ops (VADD.F32, the FP 2-reg-misc and the conversions), VRECPE/VRSQRTE, crypto, the neon-shared group, and the BF16 and dot product ops. They UNDEF for now. HWCAP_NEON stays clear until the next slice adds them, so glibc doesn't pick Neon routines.

Compared against QEMU 11.1 qemu-arm on server3:

  • 10714 generated tests, one instruction each. They are random encodings in the dp and ls groups plus the VMOV and VDUP forms, with objdump's FP and crypto forms filtered out. The inputs are random and special D register values, and base addresses at offsets 0 to 32, so misaligned hints fault. The tests compare the changed D registers, FPSCR, the base and Rm registers, the memory written, and SIGILL, SIGSEGV and SIGBUS.
    • Built for A32 and for T32, so all 10714 run in both states. 6271 of them UNDEF on both emulators.
    • The output is identical in both states.
  • A vectorized C program at -O1 and -O3 with intrinsics: vld3, vtbl3/vtbx1, saturating and rounding ops, vmlal_lane, vqdmlsl, zip/uzp and vpadd. It ran as A32 and as Thumb, and the output and the final FPSCR match.
  • Hello and the VFP tests match.
  • The signal tests differ from QEMU in the same way they did before this slice (already present at linux-user: arm kuser helpers, commpage and signal frames #333). In the same environment, one line differs: the CPSR GE bits in the handler. Change the environment size and the fault address can also move by 0x10. There are two causes, and both are in the loader:
    • ruvm doesn't provide AT_SYSINFO_EHDR yet, so the auxv is one 8 byte entry shorter and the initial stack sits 8 bytes higher. After 16 byte alignment that shows up as a 0x10 shift, depending on the environment size.
    • ruvm masks HWCAP (0x005fa0d7 against QEMU's 0x0fdfb0d7, HWCAP2 0x70 against 0x7f), so glibc picks other string routines. These leave different GE bits behind.
      The next slice addresses both, along with HWCAP_NEON.

All of the above ran on the merge commit e498d17 (this branch with main at 2a32ea6 merged in).

Checks, all on e498d17:

  • fmt
  • clippy -D warnings, native x86_64 Linux and cross for x86_64-pc-windows-gnu and aarch64-apple-darwin
  • tests: ruvm-linux-user, ruvm-target-arm and ruvm-machine-arm (which include AArch64 system mode), and ruvm-system --lib
  • the four xtasks: provenance, unsafe-audit, layers and style
  • the release build of ruvm-cli

tamnd added 2 commits October 14, 2026 21:13
Decode the Neon data-processing and load/store groups in A32 and T32,
and implement the integer parts: three registers of the same length,
two registers and a shift, three registers of different lengths, two
registers and a scalar, the two-register miscellaneous group without
the FP ops, VEXT, VTBL/VTBX, VDUP, the modified immediates, VLDn/VSTn
in all forms with QEMU's alignment checks, and VMOV between a core
register and a scalar. The ops run on the A64 vector helper through a
new a32_neon helper that maps D registers onto the Q registers.

The FP and crypto parts follow in the next slice, which also sets
HWCAP_NEON for qemu-arm.
@tamnd tamnd added this to the M7: User mode milestone Oct 15, 2026
@tamnd tamnd added kind/feature It should do something it does not. area/target Guest ISAs and CPU models. area/user-mode linux-user and bsd-user. labels Oct 15, 2026
@tamnd
tamnd merged commit d9f4ea1 into main Oct 15, 2026
3 of 12 checks passed
@tamnd
tamnd deleted the m7-a32-neon branch October 15, 2026 20:38
@tamnd tamnd mentioned this pull request Oct 15, 2026
2 of 7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/target Guest ISAs and CPU models. area/user-mode linux-user and bsd-user. kind/feature It should do something it does not.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant