Two real memory models, in increasing order of difficulty: RISC-V’s RVWMO, then IBM Power — the hardest model in the book.
5.6.1 RISC-V Weak Memory Order (RVWMO)
RVWMO rvwmo RISC-V Weak Memory Order: XC-style total memory order plus RC-style ACQUIRE/RELEASE annotations, FENCE variants, and dependency-induced orderings. defined in Chapter 5 — open in glossary can be understood as a mix of release consistency and XC. Like XC, it is defined in terms of a global memory order (a total order of all memory operations) and offers FENCE instructions. Like RC, loads and stores can carry annotations: a load can be an ACQUIRE, a store a RELEASE, and an RMW either or both. (RISC-V also specifies a TSO variant, zTSO, not covered here.)
RELEASE/ACQUIRE orderings. Each annotation comes in two strengths — RCsc and RCpc (named for sequential and processor consistency; PC is TSO’s less-formal precursor without write atomicity). Loads and stores may carry either strength; RMWs only RCsc. The annotations preserve:
- ACQUIRE → Load, Store (both ACQUIRE-RCsc and ACQUIRE-RCpc);
- Load, Store → RELEASE (both strengths); and
- RELEASE-RCsc → ACQUIRE-RCsc.
FENCE orderings. Six non-trivial variants (R = load, W = store):
| FENCE | Enforces |
|---|---|
FENCE RW,RW | everything: Load, Store → Load, Store (XC’s full FENCE) |
FENCE RW,W | Load, Store → Store |
FENCE R,RW | Load → Load, Store |
FENCE R,R | Load → Load only |
FENCE W,W | Store → Store only |
FENCE.TSO | Load → Load, Store → Store, Load → Store — not Store → Load |
An example (Table 5.11). Both mechanisms at once — C1 orders S1 → L1 with RCsc annotations; C2 orders S2 → L2 with a full FENCE; the combination makes (r1, r2) = (0, 0) impossible:
| Core C1 | Core C2 | Comments |
|---|---|---|
S1: RELEASE-RCsc x = NEW;L1: ACQUIRE-RCsc r1 = y; | S2: y = NEW;FENCE RW,RW;L2: r2 = x; | /* Initially x = y = 0. S1 → L1 via RELEASE-RCsc → ACQUIRE-RCsc; S2 → L2 via the FENCE */ |
Dependency-induced orderings. Here RVWMO is subtly stronger than XC: syntactic address, data, and control dependencies dependency-induced ordering Ordering forced by syntactic address, data, or control dependencies in RVWMO (and Power) but not in XC. defined in Chapter 5 — open in glossary induce order.
- Address (Table 5.12): C1 stores data2 = NEW,
FENCE W,W, then pointspointerat data2; C2 loads the pointer (L1) and dereferences it (L2). Though no fence separates C2’s loads, L1 → L2 is enforced because L1’s value computes L2’s address — so (r1, r2) = (&data2, 0) is impossible. - Data (Table 5.13, “load buffering”): each core loads one variable into a register and stores that register to the other variable. Can both registers read 42, out of thin air out-of-thin-air A load result with no producing store, arising from speculative load-buffering cycles; forbidden by dependency-induced ordering. defined in Chapter 5 — open in glossary ? XC, surprisingly, does not prohibit it — with no FENCE between load and store, a speculative cycle is legal:
Table 5.13’s cycle: S1 speculates that L1 will read 42 and writes 42 to y; L2 reads it; S2 writes it to x; L1 reads it — “confirming” the guess. RVWMO’s data-dependency rule (red arcs must point downward) breaks the cycle.
- Control (Table 5.14): a store that executes only if a branch on an earlier load’s value is not taken is ordered after that load — preventing a store from (indirectly) affecting the very load that decides whether it executes.
All these dependencies are syntactic (a function of register identities), not semantic — and RVWMO adds “pipeline dependencies” beyond the book’s scope.
RMWs. RISC-V has two kinds: AMOs amo RISC-V single-instruction atomic memory operation whose load and store appear consecutively in the global memory order. defined in Chapter 5 — open in glossary — single instructions (e.g., fetch-and-increment), atomic iff load and store are consecutive in the global memory order, like an XC RMW — and load-reserved / store-conditional load-reserved/store-conditional (ldr/stc) Two-instruction RMW that is atomic iff no store to the same address appears between the LdR's source store and the StC in memory order. defined in Chapter 5 — open in glossary pairs, whose atomicity is subtly weaker: if the LdR reads a value produced by store s, the pair is atomic as long as no same-address store appears between s and the StC in memory order.
Summary: a recent relaxed model combining XC’s total-order, FENCE-based skeleton with RC’s acquire/release annotations — plus dependency rules XC lacks.
5.6.2 IBM Power
Power looks superficially like XC, with four deep differences.
First — stores are performed with respect to performed w.r.t. A store is performed with respect to core Ci once Ci's loads can no longer return the pre-store value; Power orders stores per-core rather than via one total memory order. defined in Chapter 5 — open in glossary cores, not memory. A store by C1 is performed w.r.t. C2 once C2’s loads can no longer read the clobbered value. With FENCEs, C1’s stores S1, S2, S3 perform w.r.t. every core in the same order; without them, S1 may be performed w.r.t. C2 but not yet C3. Power is therefore not guaranteed to create a total memory order — the assumption every model so far shared, and the reason §5.5’s IRIW outcome becomes reachable on Power hardware without the right fences.
Second — FENCEs are cumulative cumulative fence A FENCE (Power) whose before/after sets recursively absorb other cores' accesses ordered before or after it. defined in Chapter 5 — open in glossary . For a FENCE with pre-set X and post-set Y: (a) X absorbs other cores’ accesses ordered before the FENCE (e.g., a store already performed w.r.t. this core); (b) Y absorbs accesses ordered after it by data or control dependence or later FENCEs; (c) both grow recursively across cores. (XC’s FENCEs are cumulative too — but the total memory order provides it automatically.)
Third — three FENCEs (more exist for I/O space):
HWSYNC hwsync Power's heavyweight cumulative sync ordering everything before it ahead of everything after it; required for Store→Load ordering (Dekker) and IRIW. defined in Chapter 5 — open in glossary
”Heavyweight sync”: all of X before all of Y — including Store→Load. Cumulative. The only fence strong enough for Dekker and IRIW.
LWSYNC lwsync Power's lightweight cumulative sync ordering all combinations except Store→Load; suffices for the flag idiom and causality chains. defined in Chapter 5 — open in glossary
”Lightweight sync”: loads-in-X → Y, X → stores-in-Y — everything except Store→Load. Cumulative. Enough for the flag idiom and causality chains.
ISYNC
Orders INSTRUCTIONS, not memory accesses — despite the name, not a memory fence, and not cumulative. The book avoids it.
Fourth — dependency-induced orderings, even without FENCEs: a load feeding a later load’s address orders the pair, as does a load feeding a later store’s address or data value.
The classic programs on Power
Flag idiom (Table 5.15) — LWSYNC suffices. C1: S1, S2, LWSYNC, S3
(flag); C2: spin on flag, LWSYNC, L2, L3. C1’s fence orders
stores-in-X before stores-in-Y (S1, S2 before S3 — note it does not
order S1 and S2 with each other, which isn’t needed); C2’s orders its
spin load before L2 and L3. No Store→Load order needed anywhere.
Dekker (Table 5.16) — HWSYNC required. Each core needs its store
ordered before its subsequent load — exactly the one ordering LWSYNC
lacks. With HWSYNC between each store/load pair, (r1, r2) = (0, 0) is
prevented.
Causality (Table 5.17) — cumulative LWSYNCs. Step through how the performed-w.r.t. sets grow and why r3 is always NEW:
1 / 7Power has no single memory order
Unlike XC, a Power store is not ordered by one total <m. It is "performed with respect to" (w.r.t.) each core INDIVIDUALLY: performed w.r.t. Ci once Ci's loads can no longer read the old value. Without fences, C1's store may be performed w.r.t. C2 long before C3. Watch each core's private view below.
IRIW (Table 5.18) — HWSYNCs, and cumulativity is the point. Replace
Table 5.10’s FENCEs with HWSYNC and the forbidden
r1 = NEW, r2 = 0, r3 = NEW, r4 = 0 outcome is disallowed: C3’s HWSYNC
must cumulatively order C1’s S1 before C3’s L2 — for every core,
including C4. LWSYNCs are not sufficient here.
Finally, a thought experiment: Power restricted to an HWSYNC between
every pair of memory-accessing instructions gives SC executions. It is
definitely not a recommended way to achieve performance — and a
footnote warns that FENCEs cannot restore SC on Power when multiple
access sizes are in play.
Check yourself
1.RVWMO is described as a mix of XC and RC. Which ingredients come from where?
2.Which orderings does RVWMO's FENCE.TSO enforce?
3.In the load-buffering example (Table 5.13), XC technically allows r1 = r2 = 42 "out of thin air." How does RVWMO forbid it?
4.When does RVWMO enforce same-address Load→Load ordering?
5.On Power, why does Dekker (Table 5.16) need HWSYNC when the flag idiom (Table 5.15) gets by with LWSYNC?
6.What makes a Power FENCE CUMULATIVE?