Out-of-order instruction execution: is commit order preserved?

TL:DR: memory ordering is not the same thing as out of order execution. It happens even on in-order pipelined CPUs.

In-order commit is necessary1 for precise exceptions that can roll-back to exactly the instruction that faulted, without any instructions after that having already retired. The cardinal rule of out-of-order execution is don’t break single-threaded code. If you allowed out-of-order commit (retirement) without any kind of other mechanism, you could have a page-fault happen while some later instructions had already executed once, and/or some earlier instructions hadn’t executed yet. This would make restarting execution after handing a page-fault impossible the normal way.

(In-order issue/rename and dependency-tracking takes care of correct execution in the normal case of no exceptions.)

Memory ordering is all about what other cores see. Also notice that what you quoted is only talking about committing results to the register file, not to memory.

(Footnote 1: Kilo-instruction Processors: Overcoming the Memory Wall is a theoretical paper about checkpointing state to allow rollback to a consistent machine state at some point before an exception, allowing much larger out-of-order windows without a gigantic ROB of that size. AFAIK, no mainstream commercial designs have used that, but it shows that there are in theory approaches other than strictly in-order retirement to building a usable CPU.

Apple’s M1 reportedly has a significantly larger out-of-order window than its x86 contemporaries, but I haven’t seen any definite info that it uses anything other than a very large ROB.)


Since each core’s private L1 cache is coherent with all the other data caches in the system, memory ordering is a question of when instructions read or write cache. This is separate from when they retire from the out-of-order core.

Loads become globally visible when they read their data from cache. This is more or less when they “execute”, and definitely way before they retire (aka commit).

Stores become globally visible when their data is committed to cache. This has to wait until they’re known to be non-speculative, i.e. that no exceptions or interrupts will cause a roll-back that has to “undo” the store. So a store can commit to L1 cache as early as when it retires from the out-of-order core.

But even in-order CPUs use a store queue or store buffer to hide the latency of stores that miss in L1 cache. The out-of-order machinery doesn’t need to keep tracking a store once it’s known that it will definitely happen, so a store insn/uop can retire even before it commits to L1 cache. The store buffer holds onto it until L1 cache is ready to accept it. i.e. when it owns the cache line (Exclusive or Modified state of the MESI cache coherency protocol), and the memory-ordering rules allow the store to become globally visible now.

See also my answer on Write Allocate / Fetch on Write Cache Policy

As I understand it, a store’s data is added to the store queue when it “executes” in the out-of-order core, and that’s what a store execution unit does. (Store-address writing the address, and store-data writing the data into the store-buffer entry reserved for it at allocation/rename time, so either of those parts can execute first on CPUs where those parts are scheduled separately, e.g. Intel.)

Loads have to probe the store queue so that they see recently-stored data.


For an ISA like x86, with strong ordering, the store queue has to preserve the memory-ordering semantics of the ISA. i.e. stores can’t reorder with other stores, and stores can’t become globally visible before earlier loads. (LoadStore reordering isn’t allowed (nor is StoreStore or LoadLoad), only StoreLoad reordering).

David Kanter’s article on how TSX (transactional memory) could be implemented in different ways than what Haswell does provides some insight into the Memory Order Buffer, and how it’s a separate structure from the ReOrder Buffer (ROB) that tracks instruction/uop reordering. He starts by describing how things currently work, before getting into how it could be modified to track a transaction that can commit or abort as a group.

Leave a Comment