2026-07-22
Your L1 data cache serves loads and stores in cache-line granularity — 64 bytes at a time on nearly every modern CPU. The load unit's data path is wired to fetch one cache line per cycle per port. So what happens when your 8-byte load lands at address 0x1003C, spanning bytes 60–67 of one line and 0–3 of the next?
The CPU has to issue two cache lookups, wait for both to return, then splice the results together in a merge stage before the load can retire. On Intel Skylake and later, this is called a split load and it costs roughly 5 extra cycles plus consumes two entries in the load buffer instead of one. On AMD Zen, the penalty is similar and split loads are counted separately in the performance monitor (ls_dispatch.ld_st_split).
Split stores are worse. The store buffer entry has to track two addresses, two data halves, and can't retire until both cache lines are writable. If the store crosses a 4KB page boundary, the AGU has to walk two page table entries — potentially two TLB misses — and the penalty explodes to 20–50 cycles.
Concrete example: Consider a memcpy that reads 8 bytes at a time from an unaligned source. If the source pointer is 4-byte-aligned but not 8-byte-aligned, roughly 1 in 8 loads will span a cache line. On a workload processing 10 GB of data, that's ~156 million split loads. At 5 cycles each on a 3 GHz core, you've burned 260 milliseconds of pure alignment tax — often more than the actual copy work.
Rule of thumb: A load of N bytes at address A crosses a cache line if (A mod 64) + N > 64. Align hot data structures to 64 bytes (alignas(64)) and use natural alignment for all fields. For arrays of 12-byte structs, pad to 16 — the wasted memory is cheaper than the split-access tax.
Modern CPUs try to hide this: Intel's split-line handler runs in parallel with the primary access, and AMD's load queue can coalesce a split load into two µops at rename time. But you can't beat physics. If your working set is bandwidth-bound and 20% of your loads split, you've effectively halved your L1 throughput.
Check perf stat -e ld_blocks.no_sr,ld_blocks_partial.address_alias to see if split accesses are silently stealing your cycles.
