Skip to main content

orderings

Function orderings 

Source
pub fn orderings(func: &mut Func, word: u32)
Expand description

Rewrites every ordered access into the plain access this machine already makes ordered, and leaves a barrier where the machine needs one.

This is the one pass here whose reason is a memory model rather than a missing instruction, so it is worth writing down what the model says. x86-64 is total store order. Every load is an acquire, every store is a release, and an aligned access no wider than a word is indivisible whether or not anybody asked for one. So an atomic_load at any ordering is the same mov a load is, and so is an atomic_store at every ordering except the strongest, and rewriting them into the plain access is not an approximation: it is the whole of what the machine does.

The one thing total store order does not give is a store followed by a load of a different address staying in that order, and that is exactly what sequential consistency is missing. So a sequentially consistent store is the same mov with an mfence behind it, which is the pair gcc 16.2.0 writes. The fence is left in the IR as a fence rather than written here, because what a barrier costs is a target question and crate::lower is where the target answers are.

A fence the program wrote is left alone for the same reason. Every ordering below the strongest is nothing at all on this machine and the strongest is one instruction, and both of those are decided by name in crate::lower where the instruction lives.

ยงWhy the width is checked

An access is only indivisible if the machine can do it in one go, which here means one, two, four or eight bytes at an address aligned to its own width. Anything else is a run of accesses and a run of accesses is not atomic at all, so it is left as the opcode it was and no rule covers it, which is a compile error naming the instruction. That is the right answer: an atomic access the machine cannot make atomic has no correct lowering, and a wrong one that looks right is worse than a refusal. C says the same thing through __atomic_is_lock_free.

word is how many bytes the widest indivisible access carries, which is the same number the widest move carries and is read from the machine for the reason bulk reads it.

This runs before every other pass here, so that what it produces is an ordinary load or store that the width legalisation and everything after it get to see. An ordered access at a width the machine has no register for would otherwise be a shape nothing later understands, since every pass after this one is written about load and store by name.