Memory model
WAVE uses registers, local memory, and device memory. Their scope and synchronization requirements differ.
Memory hierarchy at a glance
Section titled “Memory hierarchy at a glance”| Storage | Scope | Access |
|---|---|---|
| Registers | One thread | Register operands and wave operations |
| Local memory | One workgroup | Byte addresses |
| Device memory | Device allocation | Byte addresses |
Capacity, latency, and cache behavior depend on the target. Declare local memory with .local_memory and check the target's resource limits.
Registers
Section titled “Registers”Registers hold untyped 32-bit values. Instructions determine whether those bits represent integers, floats, or packed values. Threads exchange register values through wave operations.
mov_imm r0, 100iadd r2, r0, r1Load and store operations
Section titled “Load and store operations”Widths
Section titled “Widths”Device loads and stores support u8, u16, u32, u64, and u128. Local loads and stores support u8, u16, u32, and u64.
Loads name the destination before the address. Stores name the address before the value:
device_load_u32 r0, r1 ; load from address r1 into r0device_load_u128 r4, r1 ; load four words into r4 through r7local_load_u32 r0, r1device_store_u64 r2, r4 ; store r4 and r5 at address r2Multiword operations use consecutive registers. Keep the accessed range inside the allocation and satisfy the instruction's alignment requirements.
Cache hints
Section titled “Cache hints”Device operations accept cache hints:
| Hint | Intent |
|---|---|
cached | Reuse data through the cache hierarchy |
uncached | Request cache bypass |
streaming | Give streaming data lower cache priority |
device_load_u32.cached r0, r1device_load_u32.uncached r0, r1device_load_u32.streaming r0, r1Hints express cache policy. They do not replace atomic operations, fences, or barriers needed for synchronization. A backend maps them to the policies its target supports.
Local memory: shared memory
Section titled “Local memory: shared memory”Threads in a workgroup share local memory. Use it to exchange values, stage tiles, or store partial results.
mov_sr r0, sr_thread_id_xmov_imm r1, 4imul r2, r0, r1local_store_u32 r2, r3barrierlocal_load_u32 r4, r2The kernel must declare enough local memory for all participating threads. Insert a barrier before another thread reads the stored values.
Example: cooperative device-to-local tiling
Section titled “Example: cooperative device-to-local tiling”Each thread loads one word and stores it at its own local offset. After the barrier, threads may read the tile:
mov_sr r0, sr_thread_id_xmov_imm r1, 4imul r2, r0, r1iadd r3, r10, r2device_load_u32 r4, r3local_store_u32 r2, r4barrier
; Read the next thread's value, wrapping at the workgroup boundary.mov_imm r5, 1iadd r6, r0, r5mov_sr r7, sr_workgroup_size_ximod r6, r6, r7imul r6, r6, r1local_load_u32 r8, r6Here r10 contains the device tile's base offset. The allocation must contain one word per thread.
Atomic operations
Section titled “Atomic operations”An atomic operation updates one memory location indivisibly. Local atomics use local_atomic_*; device atomics use atomic_* with a scope.
Available atomic operations
Section titled “Available atomic operations”| Operation | Device mnemonic |
|---|---|
| Add | atomic_add |
| Subtract | atomic_sub |
| Minimum | atomic_min |
| Maximum | atomic_max |
| Bitwise AND | atomic_and |
| Bitwise OR | atomic_or |
| Bitwise XOR | atomic_xor |
| Exchange | atomic_exchange |
| Compare and swap | atomic_cas |
atomic_add r2, r1, r0, .deviceatomic_cas r2, r1, r0, r3, .deviceBoth examples return the previous value in r2. The compare-and-swap stores r3 only when the value at address r1 equals r0.
Memory scopes
Section titled “Memory scopes”A scope identifies the participants covered by an atomic operation or fence:
| Scope | Participants |
|---|---|
wave | Lanes in one wave |
workgroup | Threads in one workgroup |
device | Threads on the device |
system | Device and host participants |
Choose the scope required by the communication pattern and supported by the target.
Fences
Section titled “Fences”Fences order memory operations. They do not wait for other threads to arrive.
| Fence | Ordering |
|---|---|
fence_acquire | Acquire ordering |
fence_release | Release ordering |
fence_acq_rel | Acquire and release ordering |
fence_release .workgroupbarrierfence_acquire .workgroupWhen to use each scope
Section titled “When to use each scope”- Use
wavefor communication within a wave. - Use
workgroupfor communication within a workgroup. - Use
devicefor communication between workgroups. - Use
systemwhen the synchronization protocol includes the host.
Example: device-scope counter
Section titled “Example: device-scope counter”mov_imm r0, 1atomic_add r1, r10, r0, .deviceThe operation increments the counter at r10. Publishing other memory through a counter also requires a suitable ordering protocol; atomicity alone is insufficient.
Barrier
Section titled “Barrier”barrier synchronizes workgroup threads. All participating threads must reach the same barrier. Use it between shared-memory writes and reads by other threads, and before overwriting storage that other threads may still be reading.
Summary
Section titled “Summary”| Operation | Local memory | Device memory |
|---|---|---|
| Load | local_load_* | device_load_* |
| Store | local_store_* | device_store_* |
| Atomic update | local_atomic_* | atomic_* |
| Synchronization | Workgroup barriers and fences | Scoped atomic protocols and fences |
Next: Control flow.