blob: 3de4be7c3e0079edc070738880320a39a9dbcf95 [file] [view]
(amdgpu-dma-operations)=
# AMDGPU DMA Operations
```{contents}
:local:
```
## Introduction
DMA (or "Direct Memory Access") operations transfer data between different kinds
of memory directly without occupying registers in the invoking wave. They are
usually {ref}`asynchronous<amdgpu-async-operations>` asynchronous, and require
the user to explicitly track completion using
{ref}`asyncmarks<amdgpu-async-operations>`.
All DMA operations support the same cache modifiers as ordinary load/store
operations from registers. They cannot be performed atomically.
### GFX9 DMA
Each GFX9 DMA instruction has a synchronous counterpart (e.g.,
``@llvm.amdgcn.load.to.lds`` for ``@llvm.amdgcn.load.async.to.lds``). The
synchronous variants perform the same operation, but the compiler automatically
ensures completion before their side-effects are used.
GFX9 DMA instructions implement volatile (via ``aux/cpol`` bit 31) and
nontemporal (via metadata) as if they were loads from the global address space.
**Flat/Global Addressing**
```llvm
void @llvm.amdgcn.load[.async].to.lds.pN(
ptr addrspace(N) %src, ; base pointer to load from (per-lane)
ptr addrspace(3) %lds_base, ; LDS base pointer (wave-uniform)
i32 immarg %size, ; data byte size: 1/2/4 (12/16 for gfx950)
i32 immarg %offset, ; offset applied to both src and LDS address
i32 immarg %cpol) ; cache policy
```
Loads data from global memory to LDS. The data size can be 1, 2, or 4 bytes
(gfx950 also allows 12 or 16 bytes). The LDS address is implicitly offset by
``4 * lane_id`` bytes for sizes up to 4 bytes, and by ``16 * lane_id`` bytes
for larger sizes.
The ``%lds_base`` pointer must be wave-uniform.
The source pointer is overloaded on address space. Supported address spaces are
flat (0), global (1), and buffer fat pointer (7).
``@llvm.amdgcn.load[.async].to.lds.p7`` (buffer pointer) is lowered to
``@llvm.amdgcn.raw.ptr.buffer.load[.async].lds`` before instruction selection.
```llvm
void @llvm.amdgcn.global.load[.async].lds(
ptr addrspace(1) %src, ; global base pointer to load from (per-lane)
ptr addrspace(3) %lds_base, ; LDS base pointer (wave-uniform)
i32 immarg %size, ; data byte size: 1/2/4 (12/16 for gfx950)
i32 immarg %offset, ; offset applied to both global and LDS address
i32 immarg %cpol) ; cache policy
```
This is identical to ``@llvm.amdgcn.load[.async].to.lds.p1``.
**Buffer Addressing**
```llvm
void @llvm.amdgcn.{raw|struct}[.ptr].buffer.load[.async].lds(
%rsrc, ; buffer resource descriptor (SGPR):
; <4 x i32> or ptr addrspace(8)
ptr addrspace(3) %lds_base, ; LDS base pointer (wave-uniform)
i32 immarg %size, ; data byte size: 1/2/4 (12/16 for gfx950)
[i32 %vindex,] ; VGPR buffer index (struct variants only)
i32 %voffset, ; VGPR offset (included in bounds checking)
i32 %soffset, ; SGPR/imm offset (excluded from bounds checking)
i32 immarg %offset, ; imm offset (included in bounds checking)
i32 immarg %cpol) ; cache policy
```
Loads data from a buffer resource to LDS.
The ``%lds_base`` pointer must be wave-uniform.
The intrinsics differ in two orthogonal ways:
- **raw** vs **struct**: The ``struct`` variants add a ``%vindex`` argument for
indexed buffer addressing.
- **ptr** vs non-ptr: The ``ptr`` variants use ``ptr addrspace(8)`` for the
buffer resource descriptor; the non-ptr variants use ``<4 x i32>``.
### GFX1250
GFX1250 LDS DMA instructions implement nontemporal (via metadata) as if they
were loads from the global address space. Tensor DMA instructions do not support
volatile or nontemporal.
**Global Addressing**
```llvm
void @llvm.amdgcn.{global|cluster}.load.async.to.lds.b<N>(
ptr addrspace(1) %src, ; global base pointer to load from (per-lane)
ptr addrspace(3) %lds_base, ; LDS base pointer (per-lane)
i32 immarg %offset, ; offset applied to both global and LDS address
i32 immarg %cpol, ; cache policy
[i32 %m0]) ; workgroup broadcast mask, cluster variants only (in M0)
```
The bit-size encoded in the name can be 8, 32, 64 or 128.
Loads data from global memory to LDS. The ``%offset`` is applied to both the
global and LDS addresses.
The ``cluster`` variants add a ``%m0`` argument for workgroup broadcast. The
broadcast mask selects which workgroups within a cluster participate in the load.
```llvm
void @llvm.amdgcn.global.store.async.from.lds.b<N>(
ptr addrspace(1) %dst, ; global base pointer to store to (per-lane)
ptr addrspace(3) %lds_base, ; LDS base pointer to load from (per-lane)
i32 immarg %offset, ; offset applied to both global and LDS address
i32 immarg %cpol) ; cache policy
```
Stores data from LDS to global memory.
**Tensor Addressing**
```llvm
void @llvm.amdgcn.tensor.{load.to|store.from}.lds(
<4 x i32> %desc0, ; D# group 0
<8 x i32> %desc1, ; D# group 1
<4 x i32> %desc2, ; D# group 2 (zero-init for D# up to 2D)
<4 x i32> %desc3, ; D# group 3 (zero-init for D# up to 2D)
<8 x i32> %desc4, ; D# group 4 (reserved, use zeroinitializer)
i32 immarg %cpol) ; cache policy
```
Loads or stores data between global memory and LDS using a tensor descriptor
(D#). The descriptor is split across multiple groups. GFX1250 supports up to 4
descriptor groups; ``%desc4`` is reserved for future targets and must be
zero-initialized.
Despite the absence of ``.async`` in their names, these intrinsics are
asynchronous.
All arguments must be wave-uniform.