The Store Buffer's Store-to-Load Forwarding Cross-Line Failure: Why a Load That Spans Two Cache Lines Never Forwards

2026-09-11

Store-to-load forwarding is the fast path where a load reads its value directly from an older, still-buffered store instead of waiting for that store to reach L1. It's one of the most important tricks in a modern CPU — dependent loads that follow stores are everywhere (spills, stack traffic, pointer updates). But there's a specific case where forwarding always fails: when the load crosses a cache line boundary.

The reason is structural. The store buffer is organized around cache lines — each entry holds bytes belonging to one 64-byte line, tagged with a physical line address and a byte-mask of which bytes are valid. The forwarding CAM (content-addressable memory) matches loads against store buffer entries using that single line address. A load that straddles two lines has two line addresses. It would need to simultaneously match two different store buffer entries, merge their bytes, and combine that with data possibly still in L1 for the untouched portion. No mainstream CPU builds that hardware.

Instead, the split load is broken into two aligned halves internally. Each half tries to forward independently — but the forwarding path typically requires the entire load range to be covered by a single store. If either half touches a line where an older store exists, the load must wait for that store to drain to L1, then re-issue as a normal cache access. This is often called a split-load forwarding stall, and it costs roughly 10–20 cycles on Intel Skylake-class cores, versus 4–5 cycles for a successful forward.

Concrete example: A memcpy loop copies 8-byte words but the source pointer is misaligned by 4 bytes relative to a 64-byte line. Each load straddles two lines. If the destination of a previous iteration's store happens to alias one of those lines (common in tight in-place transforms), forwarding fails on every iteration. You'll see MEM_INST_RETIRED.SPLIT_LOADS climb, and IPC can drop by 30–50% versus the aligned version — even though every access hits L1.

Rule of thumb: A load can forward from a store only if load_start ≥ store_start, load_end ≤ store_end, and both live on the same 64-byte line. Cross a line boundary and you've bought a full store-buffer drain. Align hot loads to their natural size, and if you must do unaligned access, ensure no recent store touches either half of the split.

Key Takeaway: Store-to-load forwarding is single-line only — a load that crosses a 64-byte boundary can never forward and must wait for the store buffer to drain before the split access completes.

All newsletters