The 4K Aliasing False Dependency: Why Loads and Stores 4096 Bytes Apart Look Identical to Your CPU

2026-07-15

When a load executes speculatively before an earlier store's address is known, the CPU has to guess whether they alias. To make that decision fast, the memory disambiguation hardware compares only the low 12 bits of the addresses — the page-offset bits that don't require the TLB. If those 12 bits match, the load stalls, waiting for the store to resolve. If they differ, the load proceeds.

Twelve bits covers exactly 4096 bytes. So any two addresses that are an integer multiple of 4KB apart have identical low bits and look aliased, even when they refer to completely different pages. The store might write to virtual address 0x7f00_1040 and the load might read 0x7f01_2040 — different pages, different cache lines, no real conflict — but the low 12 bits (0x040) match, and the CPU treats the load as if it might depend on the store.

The penalty isn't a full pipeline flush; it's a partial replay. The load gets held in the load queue until the store's full physical address is computed, then re-executed. On Skylake-class cores this costs roughly 5–7 cycles per event. In a tight loop, that's a 20–40% throughput hit.

Real-world example: A common bug pattern is copying between two buffers allocated with posix_memalign(..., 4096, ...) or mmap. Both buffers get page-aligned addresses. Now every store to dst[i] aliases with the load of src[i] at the same offset. A memcpy loop that should hit ~1 element/cycle drops to ~0.7. Fix: offset one buffer by 64 bytes (a cache line) so the low 12 bits diverge.

Rule of thumb: If two hot pointers differ by exactly N × 4096 bytes and you're doing interleaved reads and writes, expect ~15% throughput loss. Check with perf stat -e ld_blocks_partial.address_alias on Intel — that counter fires once per aliasing event.

Why doesn't the CPU just compare more bits? Because bits above 12 require the TLB translation to be complete, and the whole point of speculative load execution is to not wait for that. The 12-bit compare is a deliberate accuracy-vs-latency tradeoff — the CPU accepts some false positives to avoid stalling every load on TLB latency.

AMD Zen has similar behavior but with slightly different penalty characteristics; the aliasing window is still 4KB because page size is the fundamental constraint.

Key Takeaway: Because memory disambiguation uses only the low 12 bits of an address, any two pointers separated by an exact multiple of 4KB will falsely appear to alias — silently costing 5–7 cycles per interleaved load/store pair.

All newsletters