CEP-0062: Observable Memory Accesses¶
Draft
Draft proposal for volatile-like observable memory accesses, primarily for MMIO and device registers. V1 ordinary loads and stores have no volatile or atomic behavior.
Summary¶
Catalyst should eventually decide how source code can request observable memory accesses: loads and stores that the compiler must preserve because the addressed storage may have externally visible side effects.
This proposal is about volatile-like access for memory-mapped I/O, device registers, and similar externally observed storage. It is not about inter-thread synchronization, atomic read-modify-write operations, or general memory-ordering rules.
V1 has no volatile pointer type, volatile load/store operation, memory fence, or atomic operation. Ordinary *T, *const T, and []T access does not imply that a load or store must be preserved when the value is otherwise unused.
Motivation¶
Low-level systems code sometimes reads or writes memory locations that are not ordinary program storage. A device status register may change between reads. Writing a control register may trigger hardware behavior even when no ordinary program value observes the write. If the compiler treats those accesses like ordinary memory, it may remove, merge, duplicate, or reorder them in ways that are valid for normal storage but invalid for MMIO.
Catalyst should have a deliberate design for these accesses before it promises aggressive optimization, embedded targets, kernel work, or broader C/LLVM backend behavior. The design should keep the sharpness visible: volatile-like access is a memory-effect tool, not a concurrency tool and not a general escape hatch from optimization.
Proposed Direction¶
The future design should define one coherent observable-access model.
Questions to settle:
- whether the spelling is pointer-qualified, operation-qualified, region-qualified, or API-based;
- whether observable access can apply to fields, array elements, slices, opaque pointers, or only explicitly typed pointers;
- whether observable reads and writes preserve source order only relative to other observable accesses or also relative to selected ordinary accesses;
- whether volatile-like access affects only load/store elimination and reordering, or also duplication and width-changing transformations;
- how observable access lowers through the C backend, future LLVM backend, and interpreter backend;
- how target facts represent MMIO-capable address spaces, if Catalyst eventually needs address-space distinctions;
- how diagnostics distinguish observable memory access from atomics, locks, fences, and ordinary synchronization;
- how reflection, IR, and tooling display observable-access facts.
The default direction should be narrow: observable access guarantees that the requested load or store happens as written enough for device/register interaction. It should not promise atomicity, cross-thread happens-before relationships, cache coherence, or data-race safety.
Example¶
Possible future shape if operation-qualified APIs are chosen:
const status_ptr: *const u32 = device_status_register()
const control_ptr: *u32 = device_control_register()
while volatile_load(status_ptr) & READY_BIT == 0 {
}
volatile_store(control_ptr, START_BIT)
Possible future shape if pointer-qualified types are chosen:
const status: *volatile const u32 = device_status_register()
const control: *volatile u32 = device_control_register()
while status.* & READY_BIT == 0 {
}
control.* = START_BIT
These examples are illustrative only. The proposal must choose a spelling that fits Catalyst pointer syntax, attribute syntax, compiler-intrinsic syntax, and future backend metadata.
Non-Goals¶
This proposal does not design:
- atomics;
- memory-ordering modes;
- fences;
- data-race rules;
- thread synchronization;
- locks or concurrency primitives;
- noalias or exclusivity promises.
Those features may interact with observable access later, but they need separate acceptance paths.
V1 Compatibility¶
V1 source must not rely on volatile-like behavior. Ordinary pointer and slice access remains ordinary memory access.
Active V1 docs should continue to say that:
*Tand*const Tdescribe referent mutability, not volatile or atomic behavior;- pointer and slice types do not imply backend
restrict,noalias, volatile, atomic, or synchronization metadata; - any future observable-access feature must be explicit in source and represented deliberately in SIR/IR before backend emission.
The absence of volatile-like access in V1 means embedded MMIO and device-register programming are not part of the accepted V1 language surface.