[llvm] [docs] Reflect C++'s read-write and write-read coherence rules in the LLVM memory model (PR #217849)

Fabian Ritter via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 01:49:22 PDT 2026


https://github.com/ritter-x2a created https://github.com/llvm/llvm-project/pull/217849

Currently, the LLVM IR memory model as written allows behaviors of monotonic
atomic operations that violate C++'s [read-write](https://eel.is/c++draft/basic.exec#intro.races-13) and [write-read](https://eel.is/c++draft/basic.exec#intro.races-14) coherence rules.
This PR adds similar rules to the definition of the monotonic memory ordering
to make monotonic atomics behave more like C++'s relaxed atomics.
Without this, translating C++'s relaxed atomics into LLVM's monotonic atomics
is technically incorrect.

Example litmus tests:

1: read-write coherence

```
; thread 0
  store atomic i32 1, ptr %p monotonic     ; S1

; thread 1
  %l0 = load atomic i32, ptr %p monotonic  ; L0
  store atomic i32 2, ptr %p monotonic     ; S2

; thread 2
  %l1 = load atomic i32, ptr %p monotonic  ; L1
  %l2 = load atomic i32, ptr %p monotonic  ; L2
```

Here, C++'s [read-write coherence](https://eel.is/c++draft/basic.exec#intro.races-13) rule says that
the execution where `%l0 = 1; %l1 = 2; %l2 = 1` is not allowed (L0
happens-before S2, therefore L0 must read from a store before S2 in the
modification order. If L0 reads 1 from S1, S1 must therefore be before S2 in the
modification order, so the happens-before-ordered loads L1, L2 can't read them
in the opposite order due to read-read coherence.) So far, there is nothing
ruling out this execution in the LLVM memory model.

2: write-read coherence

```
; thread 0
  store atomic i32 1, ptr %p monotonic     ; S1

; thread 1
  store atomic i32 2, ptr %p monotonic     ; S2
  %l0 = load atomic i32, ptr %p monotonic  ; L0

; thread 2
  %l1 = load atomic i32, ptr %p monotonic  ; L1
  %l2 = load atomic i32, ptr %p monotonic  ; L2
```

Here, C++'s [write-read coherence](https://eel.is/c++draft/basic.exec#intro.races-14) rule says that
the execution where `%l0 = 1; %l1 = 1; %l2 = 2` is not allowed (S2
happens-before L0, therefore L0 must read from S2 or a later store in the
modification order. If L0 reads 1 from S1, S1 must therefore be after S2 in the
modification order, so the happens-before-ordered loads L1, L2 can't read them
in the opposite order due to read-read coherence.) So far, there is nothing
ruling out this execution in the LLVM memory model, either.

The read-read coherence constraint already existed in the LangRef, I've grouped
it together with the new constraints to improve readability.
write-write coherence is missing from the list because it is already implied by
the earlier "All modification orders must be compatible with the happens-before
order." constraint.

Related change in our formal memory model: https://github.com/ROCm/formal-models/pull/3

>From 9e151d400c245e532b048c6f72b1a6b50f971ed1 Mon Sep 17 00:00:00 2001
From: Fabian Ritter <fabian.ritter at amd.com>
Date: Fri, 21 Aug 2026 04:35:45 -0400
Subject: [PATCH] [docs] Reflect C++'s read-write and write-read coherence
 rules in the LLVM memory model

Currently, the LLVM IR memory model as written allows behaviors of monotonic
atomic operations that violate C++'s [read-write](https://eel.is/c++draft/basic.exec#intro.races-13) and [write-read](https://eel.is/c++draft/basic.exec#intro.races-14) coherence rules.
This PR adds similar rules to the definition of the monotonic memory ordering
to make monotonic atomics behave more like C++'s relaxed atomics.
Without this, translating C++'s relaxed atomics into LLVM's monotonic atomics
is technically incorrect.

Example litmus tests:

1: read-write coherence

```
; thread 0
  store atomic i32 1, ptr %p monotonic     ; S1

; thread 1
  %l0 = load atomic i32, ptr %p monotonic  ; L0
  store atomic i32 2, ptr %p monotonic     ; S2

; thread 2
  %l1 = load atomic i32, ptr %p monotonic  ; L1
  %l2 = load atomic i32, ptr %p monotonic  ; L2
```

Here, C++'s [read-write coherence](https://eel.is/c++draft/basic.exec#intro.races-13) rule says that
the execution where `%l0 = 1; %l1 = 2; %l2 = 1` is not allowed (L0
happens-before S2, therefore L0 must read from a store before S2 in the
modification order. If L0 reads 1 from S1, S1 must therefore be before S2 in the
modification order, so the happens-before-ordered loads L1, L2 can't read them
in the opposite order due to read-read coherence.) So far, there is nothing
ruling out this execution in the LLVM memory model.

2: write-read coherence

```
; thread 0
  store atomic i32 1, ptr %p monotonic     ; S1

; thread 1
  store atomic i32 2, ptr %p monotonic     ; S2
  %l0 = load atomic i32, ptr %p monotonic  ; L0

; thread 2
  %l1 = load atomic i32, ptr %p monotonic  ; L1
  %l2 = load atomic i32, ptr %p monotonic  ; L2
```

Here, C++'s [write-read coherence](https://eel.is/c++draft/basic.exec#intro.races-14) rule says that
the execution where `%l0 = 1; %l1 = 1; %l2 = 2` is not allowed (S2
happens-before L0, therefore L0 must read from S2 or a later store in the
modification order. If L0 reads 1 from S1, S1 must therefore be after S2 in the
modification order, so the happens-before-ordered loads L1, L2 can't read them
in the opposite order due to read-read coherence.) So far, there is nothing
ruling out this execution in the LLVM memory model, either.

The read-read coherence constraint already existed in the LangRef, I've grouped
it together with the new constraints to improve readability.
write-write coherence is missing from the list because it is already implied by
the earlier "All modification orders must be compatible with the happens-before
order." constraint.

Related change in our formal memory model: https://github.com/ROCm/formal-models/pull/3
---
 llvm/docs/LangRef.md | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 82eebd26c0054..d203721914e30 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -4170,10 +4170,23 @@ happens-before must be perfectly overlapping to act atomically.
     read-modify-write operation M ({ref}`cmpxchg <i_cmpxchg>` and
     {ref}`atomicrmw <i_atomicrmw>`) reads from a perfectly overlapping
     `monotonic` (or stronger) write W, W must be immediately before M in
-    the relevant modification order. If one atomic read happens before
-    another perfectly overlapping atomic read and both are at least
-    `monotonic`, the later read must not see an earlier value in the
-    address's modification order. This disallows reordering of perfectly
+    the relevant modification order.
+
+    Atomic accesses that are `monotonic` (or stronger) satisfy coherence rules:
+    - read-read coherence: If one atomic read happens before another
+        perfectly overlapping atomic read and both are at least
+        `monotonic`, the later read must not see an earlier value in the
+        address's modification order.
+    - read-write coherence: If an atomic read R happens before a
+        perfectly overlapping atomic write W and both are at least
+        `monotonic`, R must not read from writes that are later than W
+        in the address's modification order.
+    - write-read coherence: If an atomic read R happens after a
+        perfectly overlapping atomic write W and both are at least
+        `monotonic`, R must not read from from writes that are earlier
+        than W in the address's modification order.
+
+    This disallows reordering of perfectly
     overlapping `monotonic` (or stronger) operations. If an address is
     written `monotonic`-ally by one thread, and other threads
     `monotonic`-ally read that address repeatedly with perfectly



More information about the llvm-commits mailing list