Wavefront-level builtins for AMD GPUs#
Wavefront-level operations give you direct access to the hardware mechanisms that move and aggregate data within a wavefront. The builtins in this topic work across both CDNA (AMD Instinct) and RDNA (AMD Radeon) architectures, and cover three areas: lane operations, wavefront reductions, and wavefront voting.
Architecture availability#
Most wavefront-level builtins are available on all AMD Instinct (CDNA) and AMD Radeon (RDNA) architectures. Some builtins — particularly Data Parallel Primitives (DPP) DPP8, cross-row permutations, and ballot width variants — are limited to specific generations. For per-builtin availability, see the architecture tables in the reference pages below.
The complete source file is available for download:
Lane operations#
Within a wavefront, lanes execute the same instruction simultaneously, but each holds its own register values. Many algorithms require lanes to exchange or replicate those values - to share a computed result, apply a cyclic shift, or reorganize data before the next computation step. The builtins in this topic cover the distinct ways of expressing that communication: reading from a named lane, moving data in a cyclic pattern, applying a compile-time-fixed permutation, and broadcasting within a fixed-size group. Each fills a different niche, and choosing the right one affects both correctness and performance.
Broadcasting from a specific lane with readlane#
When a single lane holds a value that every other lane needs - a wavefront-wide
maximum, a shared configuration parameter, a count computed by one thread -
the most direct way to share it is __builtin_amdgcn_readlane. Unlike a
shuffle, which requires every lane to participate with a relative offset,
readlane reads from one named lane regardless of who is calling, making it
the natural choice when the source is fixed rather than relative. The example
here uses it to broadcast a wavefront maximum after a __shfl_down reduction,
which is a representative case: one lane holds the answer, and all others need
it.
__builtin_amdgcn_readlane(val, lane) returns the value of val held by
the lane specified by lane. Unlike readfirstlane, which always reads
the first active lane, readlane accepts a runtime lane index. The lane
index must be uniform — the same value across all lanes in the wavefront at the
point of the call. If the index is derived from per-lane data, use
readfirstlane to promote it to a uniform value first. readfirstlane
reads from the first active lane of the wavefront, which is a deterministic choice,
so every lane in the wavefront receives the same index value and the uniformity
requirement is satisfied.
1__global__ void broadcast_readlane(const int *input, int *output, int n)
2{
3 int gid = blockIdx.x * blockDim.x + threadIdx.x;
4 int lane = threadIdx.x % warpSize;
5 int val = (gid < n) ? input[gid] : 0;
6
7 // Find the warp maximum via __shfl_down reduction.
8 int max_val = val;
9 for (int offset = warpSize / 2; offset > 0; offset >>= 1)
10 {
11 max_val = max(max_val, __shfl_down(max_val, offset));
12 }
13
14 // Broadcast the maximum from lane 0 to all lanes.
15 // The lane index must be uniform; use readfirstlane to promote a
16 // runtime-derived index to a uniform value.
17 int broadcast = __builtin_amdgcn_readlane(max_val, 0);
18
19 if (gid < n)
20 {
21 output[gid] = broadcast;
22 }
23
24 (void)lane;
25}
After a __shfl_down reduction, lane 0 holds the wavefront maximum. Passing the
literal 0 as the lane index satisfies the uniformity requirement and
broadcasts that value to every lane in the wavefront.
For the full signatures and parameter details, see readlane and readfirstlane in the shuffle and lane access reference.
Wavefront rotation using mov_dpp and ds_bpermute#
Rotation shifts every lane’s value one position around the wavefront, so lane
i receives what lane i - 1 held, and lane 0 wraps around to receive
what the last lane held. This cyclic movement is a building block for
algorithms that scan or pipeline values across lanes, such as prefix operations
or producer-consumer patterns within a wavefront. Data Parallel Primitives (DPP) is the hardware-native way to
express rotation on AMD GPUs, executing in a dedicated unit without consuming
the general instruction pipeline. On CDNA-based GPUs, a single wave_ror:1 instruction
covers the entire wave64 atomically. On RDNA-based GPUs, where wave_ror is not
available on gfx11xx and later, the same result requires two steps: a
row_ror:1 rotates within each 16-lane row, and ds_bpermute supplies
the wrap-around value at the boundary of each row.
1// wave_ror:1 (CDNA): rotates the entire warp right by one lane.
2// row_ror:1 (RDNA): rotates within each row of 16; ds_bpermute fixes wrap-around.
3#ifdef HAS_DPP_BROADCAST
4constexpr int dpp_wave_ror1 = 0x134;
5#else
6constexpr int dpp_row_ror1 = 0x121;
7#endif
8__device__ int warp_rotate_right(int val)
9{
10#ifdef HAS_DPP_BROADCAST
11 // CDNA: single wave_ror:1 rotates all lanes atomically.
12 return __builtin_amdgcn_mov_dpp(val, dpp_wave_ror1, 0xf, 0xf, false);
13#else
14 // RDNA: row_ror:1 rotates within each row of 16.
15 int rotated = __builtin_amdgcn_mov_dpp(val, dpp_row_ror1, 0xf, 0xf, false);
16
17 // ds_bpermute (byte addressing: lane k -> addr k*4) fixes up the
18 // wrap-around value at lane 0 of each row.
19 int lane = threadIdx.x % warpSize;
20 int addr = (lane == 0) ? 124 : (lane == 16) ? 60 : lane * 4;
21 int wrapped = __builtin_amdgcn_ds_bpermute(addr, val);
22
23 return (lane == 0 || lane == 16) ? wrapped : rotated;
24#endif
25}
26
27__global__ void rotate_warp(const int *input, int *output, int n)
28{
29 int gid = blockIdx.x * blockDim.x + threadIdx.x;
30 int val = (gid < n) ? input[gid] : 0;
31
32 // Rotate right warpSize times, XORing each step with the step index.
33 for (int i = 0; i < warpSize; ++i)
34 {
35 val = warp_rotate_right(val);
36 val ^= i;
37 }
38
39 if (gid < n)
40 {
41 output[gid] = val;
42 }
43}
ds_bpermute uses byte addressing: to read from lane k, pass k * 4
as the index. Lane 0 of the first row reads from lane 31 (address 124), and
lane 0 of the second row reads from lane 15 (address 60). All other lanes keep
the row_ror result unchanged.
For the full signatures and parameter details, see mov_dpp and ds_bpermute in the DPP and data-share permutation reference.
Wavefront rotation using __shfl#
The DPP rotation above is the preferred approach on AMD hardware, but the same
pattern can be expressed using __shfl. This is useful when the performance
difference is not significant for your workload. Each lane computes its source index as
(lane - 1 + warpSize) % warpSize and because __shfl accepts any uniform
lane index, the modular arithmetic produces the wrap-around without the
architecture-specific workaround that the DPP path requires.
1__device__ int warp_rotate_right_shfl(int val)
2{
3 int lane = threadIdx.x % warpSize;
4 // Rotate right: each lane reads from (lane - 1 + warpSize) % warpSize.
5 return __shfl(val, (lane - 1 + warpSize) % warpSize);
6}
7
8__global__ void rotate_warp_shfl(const int *input, int *output, int n)
9{
10 int gid = blockIdx.x * blockDim.x + threadIdx.x;
11 int val = (gid < n) ? input[gid] : 0;
12
13 // Rotate right warpSize times, XORing each step with the step index.
14 // Produces the same result as rotate_warp.
15 for (int i = 0; i < warpSize; ++i)
16 {
17 val = warp_rotate_right_shfl(val);
18 val ^= i;
19 }
20
21 if (gid < n)
22 {
23 output[gid] = val;
24 }
25}
The DPP and __shfl kernels produce identical output and can be verified against
the same CPU reference.
The two paths compile to different Instruction Set Architecture (ISA) on CDNA-based GPUs: the DPP path emits
v_mov_b32_dpp wave_rol:1, a pure register move that executes in the dedicated
DPP unit without touching memory, while the __shfl path emits
ds_bpermute_b32, which routes through the data-share unit. On RDNA-based
GPUs, where wave_ror is unavailable, the DPP path uses v_mov_b32_dpp
row_ror:1 for the within-row lanes and ds_bpermute_b32 for the cross-row
fixup; the __shfl path uses only ds_bpermute_b32. The ISA output for
both can be inspected by compiling with -save-temps and examining the
generated .s file.
Lane swap using ds_swizzle#
While readlane and rotation address individual lanes or shift the whole
wavefront by one, some algorithms need a fixed, symmetric rearrangement of groups -
for example, swapping pairs of lanes, or exchanging two halves of a tile (a
fixed-size contiguous sub-group of lanes within a wavefront).
__builtin_amdgcn_ds_swizzle is designed exactly for this: the permutation
is encoded entirely in a compile-time mask, so that the hardware can apply it in a
single instruction with no per-lane index computation. The mask specifies a
bitwise transformation of each lane index to its source, making it well-suited
to power-of-two group swaps that appear in butterfly networks, data
rearrangement before matrix operations, or paired-lane exchanges. For the full
signature, see ds_swizzle in the DPP and data-share
permutation reference.
The 16-bit mask encodes the permutation: bits [14:10] hold and_mask, bits
[9:5] hold or_mask, and bits [4:0] hold xor_mask. The source lane is
computed as (lane & and_mask) | or_mask ^ xor_mask. Setting
and_mask = 0x1F and or_mask = 0, and placing a single set bit in
xor_mask, swaps neighboring groups whose size is determined by the position
of that bit. The example demonstrates the swap pattern; the mask value and how
it determines group size are explained in the prose below.
1// ds_swizzle mask layout: bits [14:10]=and_mask, [9:5]=or_mask, [4:0]=xor_mask.
2// Source lane = (lane & and_mask) | or_mask ^ xor_mask.
3// 0x101F: and_mask=0x1F, xor_mask=0x04 - swaps neighboring groups of 4.
4constexpr int swizzle_swap_groups4 = 0x101F;
5__global__ void swizzle_swap_groups(const int *input, int *output, int n)
6{
7 int gid = blockIdx.x * blockDim.x + threadIdx.x;
8 int val = (gid < n) ? input[gid] : 0;
9
10 int swapped = __builtin_amdgcn_ds_swizzle(val, swizzle_swap_groups4);
11
12 if (gid < n)
13 {
14 output[gid] = swapped;
15 }
16}
The mask 0x101F sets xor_mask = 0x04, which applies a bitwise XOR between each lane index and
4. Lanes 0–3 read from lanes 4–7 and vice versa, lanes 8–11 read from lanes
12–15, and so on across the wavefront. Shifting the set bit changes the group size:
0x041F swaps neighboring pairs, 0x081F swaps groups of two, 0x201F
swaps groups of eight, and 0x401F swaps groups of sixteen.
For the full signature and parameter details, see ds_swizzle in the DPP and data-share permutation reference.
Wavefront reductions#
A wavefront reduction combines a value held by each lane into a single scalar
result. This pattern appears constantly in GPU kernels - summing partial
products, finding a maximum across a tile, counting active threads - and the
efficiency of the reduction matters because it often sits in the critical path
of a kernel. The three implementations below all express the same butterfly
pattern, where lanes exchange values with increasingly distant partners until
one lane holds the aggregate. Still, they differ significantly in how directly they
map to hardware. The first two reduce floating-point values and show the
progression from shuffle-based code to hardware-native DPP. The third
uses an unsigned integer reduction to demonstrate wave_reduce_add_u32, the
single-instruction form currently available in the compiler. Understanding all
three lets you choose the right level of abstraction for your target and
performance requirements.
Reduction using __shfl_down#
__shfl_down is the most readable starting point for wavefront reductions. It
reads from a lane a fixed offset ahead of the current lane, which maps directly
onto the butterfly pattern when called in a loop that halves the offset on each
step. The code structure closely mirrors the algorithm’s logical structure,
making it straightforward to reason about and maintain. The kernel is
templated on WarpSize, a compile-time constant passed at the call site,
which allows the compiler to fully unroll the reduction loop and makes the
code adapt to wave32 and wave64 without modification. This makes
__shfl_down the right choice when clarity and
simplicity matter, or as a reference implementation against which a more
hardware-specific version can be verified.
1template<int WarpSize>
2__device__ float shfl_down_reduce(float val)
3{
4 // Halve the active offset each step until all lanes have contributed.
5 // WarpSize is a compile-time constant, allowing the compiler to fully
6 // unroll this loop.
7 for (int offset = WarpSize / 2; offset > 0; offset >>= 1)
8 {
9 val += __shfl_down(val, offset);
10 }
11 return val;
12}
13
14template<int WarpSize>
15__global__ __launch_bounds__(block_size)
16void reduce_shfl_down(const float *input, float *output, int n)
17{
18 int gid = blockIdx.x * blockDim.x + threadIdx.x;
19 int lane = threadIdx.x % WarpSize;
20 int warpid = threadIdx.x / WarpSize;
21
22 float val = (gid < n) ? input[gid] : 0.0f;
23 val = shfl_down_reduce<WarpSize>(val);
24
25 // Collect one partial result per warp into shared memory, then reduce
26 // those with the first warp.
27 extern __shared__ float sdata[];
28 int num_warps = blockDim.x / WarpSize;
29 if (lane == 0)
30 {
31 sdata[warpid] = val;
32 }
33 __syncthreads();
34
35 if (warpid == 0)
36 {
37 val = (lane < num_warps) ? sdata[lane] : 0.0f;
38 val = shfl_down_reduce<WarpSize>(val);
39 }
40
41 if (threadIdx.x == 0)
42 {
43 output[blockIdx.x] = val;
44 }
45}
After the loop, lane 0 holds the sum of all lanes in the wavefront. The kernel uses a two-phase structure: each wavefront reduces its slice independently, lane 0 writes its partial result to shared memory, and the first wavefront reduces those partials to the block result.
Reduction using mov_dpp#
When targeting supported AMD GPUs specifically, Data Parallel Primitives offer a
faster path. __builtin_amdgcn_mov_dpp moves data between lanes according
to a DPP control word, executing in a dedicated hardware unit rather than the
general instruction pipeline used by shuffle operations. The same butterfly
pattern as above can be expressed with DPP control words, and the result is a
reduction that makes better use of the hardware’s data movement capabilities.
The trade-off is that DPP instructions expose architectural differences directly:
broadcast instructions are available on gfx9xx targets (CDNA), but not on
gfx10xx and later (RDNA, wave32), so the HAS_DPP_BROADCAST macro selects the
appropriate path at compile time.
1// DPP control words for butterfly reduction steps.
2// quad_perm and row_ror steps work on both CDNA and RDNA.
3// row_bcast steps are CDNA only; ds_swizzle mask 0x1e0 is the RDNA fallback.
4constexpr int dpp_quad_perm_1032 = 0xb1;
5constexpr int dpp_quad_perm_2301 = 0x4e;
6constexpr int dpp_row_ror4 = 0x124;
7constexpr int dpp_row_ror8 = 0x128;
8#ifdef HAS_DPP_BROADCAST
9constexpr int dpp_row_bcast15 = 0x142;
10constexpr int dpp_row_bcast31 = 0x143;
11#else
12constexpr int swizzle_bcast15 = 0x1e0;
13#endif
14template<int WarpSize>
15__device__ float dpp_warp_reduce(float val)
16{
17 // Reinterpret float bits as int for DPP and swizzle intrinsics.
18 auto as_int = [](float f) { return __builtin_bit_cast(int, f); };
19 auto as_float = [](int i) { return __builtin_bit_cast(float, i); };
20
21 // Steps 1-2: combine adjacent pairs within groups of 4.
22 val += as_float(__builtin_amdgcn_mov_dpp(as_int(val), dpp_quad_perm_1032, 0xf, 0xf, false));
23 val += as_float(__builtin_amdgcn_mov_dpp(as_int(val), dpp_quad_perm_2301, 0xf, 0xf, false));
24 // Steps 3-4: combine groups of 4 into a row of 16.
25 val += as_float(__builtin_amdgcn_mov_dpp(as_int(val), dpp_row_ror4, 0xf, 0xf, false));
26 val += as_float(__builtin_amdgcn_mov_dpp(as_int(val), dpp_row_ror8, 0xf, 0xf, false));
27
28#ifdef HAS_DPP_BROADCAST
29 // Steps 5-6 (CDNA): combine two rows of 16 into the full wave64 result.
30 val += as_float(__builtin_amdgcn_mov_dpp(as_int(val), dpp_row_bcast15, 0xa, 0xf, false));
31 val += as_float(__builtin_amdgcn_mov_dpp(as_int(val), dpp_row_bcast31, 0xc, 0xf, false));
32#else
33 // Step 5 (RDNA): ds_swizzle combines the two rows of the wave32 warp.
34 val += as_float(__builtin_amdgcn_ds_swizzle(as_int(val), swizzle_bcast15));
35#endif
36
37 return val;
38}
39
40template<int WarpSize>
41__global__ __launch_bounds__(block_size)
42void reduce_dpp(const float *input, float *output, int n)
43{
44 int gid = blockIdx.x * blockDim.x + threadIdx.x;
45 int lane = threadIdx.x % WarpSize;
46 int warpid = threadIdx.x / WarpSize;
47
48 float val = (gid < n) ? input[gid] : 0.0f;
49 val = dpp_warp_reduce<WarpSize>(val);
50
51 extern __shared__ float sdata[];
52 int num_warps = blockDim.x / WarpSize;
53 if (lane == WarpSize - 1)
54 {
55 sdata[warpid] = val;
56 }
57 __syncthreads();
58
59 if (warpid == 0)
60 {
61 val = (lane < num_warps) ? sdata[lane] : 0.0f;
62 val = dpp_warp_reduce<WarpSize>(val);
63 }
64
65 if (threadIdx.x == WarpSize - 1)
66 {
67 output[blockIdx.x] = val;
68 }
69}
The first two steps use quad_perm control words, which exchange lanes within
groups of four. Steps three and four use row_ror rather than row_shr:
rotation wraps lanes within the row boundary, whereas a shift leaves destination
registers undefined when the source is out of range. On RDNA, where DPP
broadcasts are unavailable, ds_swizzle with mask 0x1e0 replicates the
value held by lane 15 across lanes 16–31, combining the two rows of the wave32
wavefront in a single instruction. The control word constants used in the example
(0xb1, 0x4e, 0x124, and so on) are user-defined values derived from
the DPP control word encoding; they are not predefined by HIP or LLVM. For the
full DPP control word encoding and available patterns, refer to the Data Parallel
Primitives chapter of the
CDNA3 ISA
or
RDNA3 ISA.
Reduction using wave_reduce_add_u32#
Both implementations above express the butterfly pattern explicitly in code,
requiring you to select control words, handle the architecture split, and manage
the reduction steps yourself. __builtin_amdgcn_wave_reduce_add_u32
encapsulates all of that: you supply the value and a strategy hint, and the
builtin handles the reduction without you needing to implement or maintain the
underlying pattern. This represents the most hardware-specific end of the
spectrum - the implementation details are handled by the compiler and runtime
rather than by your code. Note that the wave reduce builtins currently cover
integer and bitwise operations; for float workloads, the DPP path above remains the recommended
approach.
1template<int WarpSize>
2__global__ __launch_bounds__(block_size)
3void reduce_wave(const unsigned int *input, unsigned int *output, int n)
4{
5 int gid = blockIdx.x * blockDim.x + threadIdx.x;
6 int lane = threadIdx.x % WarpSize;
7 int warpid = threadIdx.x / WarpSize;
8
9 unsigned int val = (gid < n) ? input[gid] : 0u;
10
11 // Reduces val across all active lanes in a single instruction.
12 // The result is broadcast to every lane.
13 unsigned int sum = __builtin_amdgcn_wave_reduce_add_u32(val, 0);
14
15 extern __shared__ unsigned int sdataui[];
16 int num_warps = blockDim.x / WarpSize;
17 if (lane == 0)
18 {
19 sdataui[warpid] = sum;
20 }
21 __syncthreads();
22
23 if (warpid == 0)
24 {
25 sum = (lane < num_warps) ? sdataui[lane] : 0u;
26 sum = __builtin_amdgcn_wave_reduce_add_u32(sum, 0);
27 }
28
29 if (threadIdx.x == 0)
30 {
31 output[blockIdx.x] = sum;
32 }
33}
The second argument is a strategy hint: 0 lets the compiler choose, 1
requests the iterative strategy, and 2 requests the DPP-based strategy.
For the full signature and parameter details, see wave_reduce_add_u32 in the wavefront reduction reference.
Wavefront voting#
Lane operations move data between lanes, and reductions aggregate it. Wavefront
voting answers a different question: which lanes satisfy a condition, and what
can the wavefront do with that information collectively? The ballot builtin
captures the answer as a bitmask - one bit per lane - which can then be
inspected, counted, or used to coordinate writes. The mbcnt builtin
builds on this by counting the number of lanes before the current one that have their bit
set, giving each qualifying lane a unique sequential index. Together, ballot and
mbcnt is the standard mechanism for stream compaction within a wavefront: filtering
a set of values to only those that pass a predicate, and writing them
contiguously to an output buffer without gaps or collisions, all without shared
memory or barriers.
Compaction index using ballot and mbcnt#
1__global__ void compaction_index(const int *input, int *output, int n)
2{
3 int gid = blockIdx.x * blockDim.x + threadIdx.x;
4 int lane = threadIdx.x % warpSize;
5 int warpid = threadIdx.x / warpSize;
6 int val = (gid < n) ? input[gid] : 0;
7
8 bool keep = (gid < n) && (val > 0);
9 int index = 0;
10
11#ifdef HAS_DPP_BROADCAST
12 // wave64 (CDNA): chain mbcnt_lo and mbcnt_hi over the 64-bit mask.
13 unsigned long long mask = __builtin_amdgcn_ballot_w64(keep);
14 unsigned int lo = static_cast<unsigned int>(mask);
15 unsigned int hi = static_cast<unsigned int>(mask >> 32);
16 index = __builtin_amdgcn_mbcnt_lo(lo, 0);
17 index = __builtin_amdgcn_mbcnt_hi(hi, index);
18#else
19 // wave32 (RDNA): mbcnt_lo over the 32-bit mask suffices.
20 unsigned int mask = __builtin_amdgcn_ballot_w32(keep);
21 index = __builtin_amdgcn_mbcnt_lo(mask, 0);
22#endif
23
24 // Compute per-warp base offsets for contiguous compacted output.
25 extern __shared__ int sdatai[];
26 int num_warps = blockDim.x / warpSize;
27 int warp_count = __builtin_amdgcn_readlane(index + (keep ? 1 : 0), warpSize - 1);
28 if (lane == 0)
29 {
30 sdatai[warpid] = warp_count;
31 }
32 __syncthreads();
33
34 int warp_base = 0;
35 for (int w = 0; w < warpid; ++w)
36 {
37 warp_base += sdatai[w];
38 }
39
40 if (keep)
41 {
42 output[blockIdx.x * blockDim.x + warp_base + index] = val;
43 }
44
45 (void)num_warps;
46}
mbcnt_hi takes the upper 32 bits of the mask and the result of mbcnt_lo
as its accumulator, so the final index is the count of passing lanes strictly
below the current lane across the full 64-bit mask. Lanes where the predicate
is false receive an index, too, but should not write to the output.
For the full signatures and parameter details, see ballot_w64 and mbcnt_lo / mbcnt_hi in the wavefront voting reference.
Compile and run:
amdclang++ -O3 -std=c++17 --offload-arch=gfx942 \
wavefront_builtins.hip -o wavefront_builtins
./wavefront_builtins
Note
The example above targets CDNA3 (gfx942, wave64). Replace
--offload-arch with the appropriate target for your GPU — for example,
gfx90a for CDNA2 or gfx1200 for RDNA4 (wave32). The __shfl* builtins work on all architectures; the DPP-specific code
paths are guarded by architecture macros in the example file.
Naming convention#
Wavefront-level builtins come in two families:
HIP wrappers use the __shfl prefix:
__shfl[_up|_down|_xor](val, offset_or_lane, width)
The suffix indicates the direction or mode: _up reads from a lower lane,
_down from a higher lane, _xor reads from a lane whose index is the bitwise XOR of
the current lane index and a mask, and no suffix reads from an absolute lane
index.
Compiler builtins use the __builtin_amdgcn_ prefix and map
directly to ISA instructions:
__builtin_amdgcn_<operation>(args...)
Key operation names:
readlane/readfirstlane/writelane– named lane accessmov_dpp/update_dpp/mov_dpp8– Data Parallel Primitivesds_swizzle/ds_permute/ds_bpermute– data-share permutationspermlane16/permlanex16/permlane64– cross-row permutationsballot_w64/ballot_w32– wavefront votingmbcnt_lo/mbcnt_hi– masked bit count (compaction index)wave_reduce_<op>_<type>– single-instruction wavefront reductions, where<op>isadd,sub,min,max,and,or, orxor, and<type>isu32,u64,i32,i64,b32, orb64
Use the __shfl* family for standard shuffle operations.
Use the __builtin_amdgcn_* intrinsics when you need a specific hardware
feature (DPP, ds_swizzle, wavefront voting) or when the ISA instruction gives
measurable performance benefit.
Wavefront builtin reference#
Each reference page documents the full signature, parameter details, and architecture support for every builtin in that family.
Family |
Description |
|---|---|
|
|
|
|
|
|
|
|
|