Background
cmd/compile's inlined arm64 struct/array copy (OpARM64LoweredMove/LoweredMoveLoop) already uses NEON paired loads/stores (FLDPQ/FSTPQ) as of CL 692315 (merged 2025-10-15, benchmarked on a Raspberry Pi 5 / Cortex-A76). The out-of-line runtime.memmove function body (src/runtime/memmove_arm64.s, used for slice append/copy, larger struct copies the compiler can't inline, etc.) still uses only paired scalar LDP/STP for every size above 16 bytes — it never touches a V/Q register.
Prior art
CL 692295 ("runtime: optimize memmove using SIMD on arm64", Fannie Zhang, ARM) already proposes exactly this: a faithful port of the existing memmove_arm64.s algorithm — same 16-byte alignment fixup, same software-pipelined loop64, same backward/overlap path — with every LDP/STP swapped for FLDPQ/FSTPQ. It shows solid wins (~25-45%) from 128B up through the largest size tested (64KiB), benchmarked on Neoverse N2.
The CL got a thorough, cordial review from Vasiliy Leonenko (who also separately authored and landed the compiler-side CL 692315 above), including a prototyped alternative with different instruction merging that the author compared against and found didn't beat the ARM-optimized-routines-derived approach. The thread ended amicably in August 2025 with no unresolved technical objection, no Code-Review score either way, and no activity since — it appears to have stalled for lack of a maintainer decision rather than for cause. Given it's now a year stale, I'd like to help move this forward rather than let a second contributor's effort go the same way.
What we found benchmarking independently
Using an isolated micro-benchmark (same loop shape, decoupled from memmove's alignment/overlap machinery, so as not to just re-derive CL 692295's own numbers) across AWS Graviton3/4/5 (Neoverse V1/V2/V3) plus an Ampere Altra (Neoverse N1), with benchstat-verified significance (p=0.001 throughout, n=7):
- NEON wins cleanly on all four cores from 128B up to ~32KiB, no exceptions.
- Above ~32–48KiB (roughly L1D capacity on the V-series cores), V1/V2/V3 flip to a small (~1.5–2%) scalar advantage that persists out to at least 1MiB. N1 does not flip — it keeps favoring NEON at every size tested, consistent with CL 692295's own N2 data showing wins persisting to 64KiB (N-series cores appear not to hit the same crossover V-series cores do).
- There's also a small, reproducible NEON regression specific to Neoverse V3 in the 256–512B range (up to +8.9%) that doesn't show up on V1/V2/N1 — a real hardware quirk, not benchmark noise (confirmed identically across two independent harness versions).
This suggests CL 692295's unconditional "NEON for everything above 128B" is very likely a net win everywhere it's been tested, but may be leaving a small amount of performance on the table on newer V-series hardware at large sizes where it hasn't been tested — and that a size-gated variant (roughly 128B–32KiB, falling back to the existing scalar path outside that range) may be the better default if a single implementation has to serve all arm64 cores.
Proposal
Revive this work — either by getting CL 692295 unstuck as-is, or with a follow-up CL building directly on its approach (same technique, explicitly crediting Fannie Zhang's original patch and Vasiliy Leonenko's review) that adds the size gate above. Happy to put together the latter and/or offer our cross-generation benchmark data as review input on the original CL — whichever the maintainers/original author would find more useful.
Background
cmd/compile's inlined arm64 struct/array copy (OpARM64LoweredMove/LoweredMoveLoop) already uses NEON paired loads/stores (FLDPQ/FSTPQ) as of CL 692315 (merged 2025-10-15, benchmarked on a Raspberry Pi 5 / Cortex-A76). The out-of-lineruntime.memmovefunction body (src/runtime/memmove_arm64.s, used for sliceappend/copy, larger struct copies the compiler can't inline, etc.) still uses only paired scalarLDP/STPfor every size above 16 bytes — it never touches aV/Qregister.Prior art
CL 692295 ("runtime: optimize memmove using SIMD on arm64", Fannie Zhang, ARM) already proposes exactly this: a faithful port of the existing
memmove_arm64.salgorithm — same 16-byte alignment fixup, same software-pipelinedloop64, same backward/overlap path — with everyLDP/STPswapped forFLDPQ/FSTPQ. It shows solid wins (~25-45%) from 128B up through the largest size tested (64KiB), benchmarked on Neoverse N2.The CL got a thorough, cordial review from Vasiliy Leonenko (who also separately authored and landed the compiler-side CL 692315 above), including a prototyped alternative with different instruction merging that the author compared against and found didn't beat the ARM-optimized-routines-derived approach. The thread ended amicably in August 2025 with no unresolved technical objection, no Code-Review score either way, and no activity since — it appears to have stalled for lack of a maintainer decision rather than for cause. Given it's now a year stale, I'd like to help move this forward rather than let a second contributor's effort go the same way.
What we found benchmarking independently
Using an isolated micro-benchmark (same loop shape, decoupled from
memmove's alignment/overlap machinery, so as not to just re-derive CL 692295's own numbers) across AWS Graviton3/4/5 (Neoverse V1/V2/V3) plus an Ampere Altra (Neoverse N1), withbenchstat-verified significance (p=0.001 throughout, n=7):This suggests CL 692295's unconditional "NEON for everything above 128B" is very likely a net win everywhere it's been tested, but may be leaving a small amount of performance on the table on newer V-series hardware at large sizes where it hasn't been tested — and that a size-gated variant (roughly 128B–32KiB, falling back to the existing scalar path outside that range) may be the better default if a single implementation has to serve all arm64 cores.
Proposal
Revive this work — either by getting CL 692295 unstuck as-is, or with a follow-up CL building directly on its approach (same technique, explicitly crediting Fannie Zhang's original patch and Vasiliy Leonenko's review) that adds the size gate above. Happy to put together the latter and/or offer our cross-generation benchmark data as review input on the original CL — whichever the maintainers/original author would find more useful.