Motivation / the Problem
So far, the LangRef hasn’t been clear on the semantics of partially overlapping
concurrent atomics in LLVM IR (specifically: a set of accesses marked as
atomic that would be in a data race if they weren’t atomic and not all of
them access the exact same set of bytes).
What loads read is defined in terms of individual bytes, but the memory ordering
constraints are formulated closely to the C/C++ (and Java for unordered)
memory model, where partially overlapping atomics are not possible. It’s not
obvious how concepts like C/C++'s per-location total modification order for
monotonic accesses map to accesses that can partially overlap. While C/C++
relies on the modification order to ensure that atomics cannot tear (i.e.,
atomic reads return bytes from two or more atomic writes), our IR semantics (as
written) currently does not guarantee this in the presence of partially
overlapping accesses.
Proposed Solution
PR #204329 proposes a solution to this problem: It specifies that concurrent
overlapping atomics must access the exact same set of bytes to act atomically.
If they don’t, they form a data race (i.e., participating loads read undef for
affected bytes). This empowers the rest of the specification to imply that
monotonic (or stronger) accesses do not tear. The PR also adds a constraint to
ensure non-tearing for unordered atomic accesses.
Impact on the Project
This assumption is already implicitly baked into the compiler-rt implementation
of the __atomic_load/__atomic_store functions for the typical libcall
lowering for too-wide or misaligned atomic accesses: Before the actual access,
it only locks a lock that is derived from the start byte of the accessed memory
region. If the access crosses a cache-line boundary, this lock does not protect
from interfering partially overlapping atomics that don’t start in the same
cache line.
The proposed semantics implies that transformations that merge adjacent atomic
loads/stores into wider atomic loads/stores are generally incorrect.
Without the requirement that concurrent atomics must access exactly the same or
entirely different bytes, formulating what atomicity, modification orders,
sequential consistency, etc. mean in LLVM IR would become a lot more complicated
(and an open research problem as far as I’m aware).
Open Questions
I’d be interested to hear if this constraint has been implicitly assumed to hold
by the community, or if partially overlapping atomic accesses are assumed to be
well-defined and act atomically.
For awareness: @nhaehnle @ssahasra @Pierre-vh @nikic @jyknight @gonzalobg @efriedma-quic @RalfJung