2026-07-04
On modern x86 cores, integer register-to-register moves (mov rax, rbx) are famously "free" — the renamer just points rax's logical entry at rbx's physical register, zero execution ports consumed, zero latency. You'd expect the same for movaps xmm0, xmm1. You'd often be wrong.
Why FP move elimination is harder. Integer moves are trivially eliminable because integer physical registers hold exactly one value with one meaning. FP/vector registers are messier:
movaps into a 256-bit YMM register must zero the upper 128 bits. That's not a rename — that's a value transformation. The renamer would need to track "zero-extended from 128" as metadata.cvtps2pd-like near-moves) touch rounding state. Renamer can't reason about that.What actually happens on Intel. Sandy Bridge eliminated integer moves but not FP moves. Ivy Bridge added elimination for movaps/movapd/movdqa between XMM registers — but only when the destination isn't being widened. Skylake broadened this to YMM. Ice Lake pulled some elimination back because tracking the widening state cost more rename bandwidth than it saved. Alder Lake's P-cores eliminate register-to-register vector moves; E-cores don't.
Concrete example. A hot loop with a manually unrolled reduction:
movaps xmm2, xmm0 — eliminated on Skylake, 0 cycles, 0 port pressurevmovaps ymm2, ymm0 — eliminated on Skylake, 0 cyclesvmovaps ymm2, xmm0 (implicit zero-extend of upper) — not eliminated, executes on port 5, 1 cycle latency, ~0.33 cycle throughputThat third form is common in code that mixes SSE and AVX intrinsics. A vectorizer that emits it inside a tight loop can burn port 5 bandwidth on what looks like a "free" copy — and port 5 is often the shuffle port, which you already needed for real work.
Rule of thumb. Same-width vector moves between architectural registers on modern P-cores: assume free. Any move that changes width, involves a mask register, or crosses the SSE/AVX boundary: assume it costs a real µop on a shuffle port. If your profiler shows unexpected port 5 pressure in vector code, grep the disassembly for narrowing/widening moves before blaming the shuffles.
