std/atomic
import std/atomic to use it. Source: src/std/atomic.iyi at v0.18.0.
The prelude's Atomic(T) has six verbs and one ordering, sequentially consistent, with no parameter to weaken it; it records that a weaker spelling arrives "as its own verb rather than a parameter, so a call site says what it means". This module is those verbs. Each name carries its ordering as a suffix — add_relaxed, get_acquire, set_release, swap_acq_rel, compare_and_set_acq_rel — so the ordering is a constant the compiler emits as that one instruction, never a runtime branch, and a reader of the call site does not have to look up an argument.
The suffixes: _relaxed is atomic and nothing more (LLVM's monotonic); _acquire is a load nothing after it may move before; _release is a store nothing before it may move after; _acq_rel is both, for a read-modify-write. A load has no release half and a store no acquire half, so get has two weaker spellings and set two; the read-modify-writes have four. compare_and_set_* names the success ordering; the failure ordering is the strongest a failed exchange can carry (acquire under _acquire/_acq_rel, relaxed otherwise).
The bitwise verbs and, nand, xor, max, min are sequentially consistent like the prelude's, and answer what the word held before. Bitwise or is spelled bitwise_or: .or is iyi's recovery keyword (expr.or { fallback }) and cannot be a method name. max/min pick the signed or unsigned instruction from T at compile time.
Atomic.fence is a full fence; fence_acquire, fence_release and fence_acq_rel are the weaker ones. There is no relaxed fence: LLVM has none and neither does the hardware.
T is what the prelude admits: Int32, Int64, UInt8 or UInt64. There is no Atomic(Bool) and no flag type here; the prelude refuses the instantiation, and a flag is a UInt8 word with swap.
Atomic(T)struct, reopened
struct ::Atomic(T)
def add_acq_rel(value : T) : T
def add_acquire(value : T) : T
def add_relaxed(value : T) : T
def add_release(value : T) : T
# `word &= value`; answers what the word held before.
def and(value : T) : T
# `word |= value`; answers what the word held before.
def bitwise_or(value : T) : T
def compare_and_set_acq_rel(expected : T, desired : T) : Tuple(T, Bool)
def compare_and_set_acquire(expected : T, desired : T) : Tuple(T, Bool)
# `compare_and_set` at each weaker ordering: if the word holds
# `expected` it now holds `desired`; answers what the word held and
# whether the exchange happened.
def compare_and_set_relaxed(expected : T, desired : T) : Tuple(T, Bool)
def compare_and_set_release(expected : T, desired : T) : Tuple(T, Bool)
# A full fence: nothing crosses it in either direction.
def self.fence : Nil
# Both halves, without the total order of `fence`.
def self.fence_acq_rel : Nil
# Nothing after this fence moves before it.
def self.fence_acquire : Nil
# Nothing before this fence moves after it.
def self.fence_release : Nil
# The word, read once; nothing after the read moves before it.
def get_acquire : T
# The word, read once, atomic and nothing more.
def get_relaxed : T
# `word = max(word, value)`, signed or unsigned as `T` is; answers what
# the word held before.
def max(value : T) : T
# `word = min(word, value)`, signed or unsigned as `T` is; answers what
# the word held before.
def min(value : T) : T
# `word = ~(word & value)`; answers what the word held before.
def nand(value : T) : T
# The word, written once, atomic and nothing more.
def set_relaxed(value : T) : Nil
# The word, written once; nothing before the write moves after it.
def set_release(value : T) : Nil
def sub_acq_rel(value : T) : T
def sub_acquire(value : T) : T
def sub_relaxed(value : T) : T
def sub_release(value : T) : T
def swap_acq_rel(value : T) : T
def swap_acquire(value : T) : T
def swap_relaxed(value : T) : T
def swap_release(value : T) : T
# `word ^= value`; answers what the word held before.
def xor(value : T) : T
endIyiAtomicstruct, reopened
struct ::IyiAtomic
def self.fence(ordering : Symbol, singlethread : Bool) : Nil
end
iyi: the weaker atomic verbs, and the bitwise ones, on the prelude's
Atomic(T).