alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
warp.hpp
Go to the documentation of this file.
1/* Copyright 2025 Sergei Bastrakov, David M. Rogers, Bernhard Manfred Gruber, Aurora Perego, Mehmet Yusufoglu, René
2 * Widera SPDX-License-Identifier: MPL-2.0
3 *
4 * Bridges runtime accelerator instances to the trait-based warp intrinsics so kernels can call them without tags.
5 * Exposes device-safe `alpaka::onAcc::warp::*` wrappers for ballots, shuffles, and lane queries.
6 * Reuses the compile-time warp trait specialisations instead of duplicating backend-specific logic in kernels.
7 * Supplies a uniform warp API across CUDA, HIP, SYCL, and host-emulation accelerators.
8 *
9 * Some example usages:
10 * - consteval `alpaka::getWarpSize(api::Cuda{}, deviceKind::NvidiaGpu{})` for tag-driven compile-time logic.
11 * - device-side `alpaka::onAcc::warp::getSize(acc)` to query the active warp inside a kernel.
12 * - device-side `alpaka::onAcc::warp::shfl(acc, 42, 0u) == 42`
13 */
14
15#pragma once
16
17#include "alpaka/Vec.hpp"
18#include "alpaka/interface.hpp"
19#include "alpaka/onAcc/Acc.hpp"
21#include "alpaka/tag.hpp"
22
23#include <cstdint>
24
25namespace alpaka::onAcc::warp
26{
27 /** Return the bit-mask of active lanes for the warp associated with the accelerator.
28 *
29 * @return bit mask where the Nth bit is set to 1 if the corresponding thread is participating the call. The return
30 * type can be 64bit or 32bit depending on the API.
31 */
32 template<alpaka::onAcc::concepts::Acc T_Acc>
33 constexpr auto activemask(T_Acc const& acc) -> std::conditional_t<T_Acc::getWarpSize() <= 32u, uint32_t, uint64_t>
34 {
35 using Acc = ALPAKA_TYPEOF(acc);
36 using Api = ALPAKA_TYPEOF(acc[object::api]);
37 return internal::Activemask::Op<Acc, Api>{}(acc, Api{});
38 }
39
40 /** Return the lane index of the current thread within its warp. */
41 constexpr uint32_t getLaneIdx(alpaka::onAcc::concepts::Acc auto const& acc)
42 {
43 return internal::getLaneIdx(acc);
44 }
45
46 /** Return the warp index within the block. */
47 constexpr uint32_t getWarpIdx(alpaka::onAcc::concepts::Acc auto const& acc)
48 {
49 return internal::getWarpIdx(acc);
50 }
51
52 /** Evaluates predicate for all active threads of the warp
53 *
54 * It follows the logic of __all_sync(__activemask(), predicate) in CUDA but returns a boolean.
55 *
56 * Note:
57 * * The programmer must ensure that all threads calling this function are executing
58 * the same line of code. In particular, it is not portable to write
59 * if(a) {all} else {all}.
60 *
61 * @param predicate The predicate value for current thread.
62 * @return true if all threads predicate non zero, else false
63 */
64 constexpr bool all(alpaka::onAcc::concepts::Acc auto const& acc, int32_t predicate)
65 {
66 using Acc = ALPAKA_TYPEOF(acc);
67 using Api = ALPAKA_TYPEOF(acc[object::api]);
68 return internal::All::Op<Acc, Api>{}(acc, Api{}, predicate);
69 }
70
71 /** Evaluates predicate for all active threads of the warp.
72 *
73 * It follows the logic of __any_sync(__activemask(), predicate) in CUDA but returns a boolean.
74 *
75 * Note:
76 * * The programmer must ensure that all threads calling this function are executing
77 * the same line of code. In particular, it is not portable to write
78 * if(a) {any} else {any}.
79 *
80 * @param predicate The predicate value for current thread.
81 * @return true if at least one threads predicate is non zero, else false
82 */
83 constexpr bool any(alpaka::onAcc::concepts::Acc auto const& acc, int32_t predicate)
84 {
85 using Acc = ALPAKA_TYPEOF(acc);
86 using Api = ALPAKA_TYPEOF(acc[object::api]);
87 return internal::Any::Op<Acc, Api>{}(acc, Api{}, predicate);
88 }
89
90 /** Evaluates predicate for all non-exited threads in a warp and returns
91 * a 32- or 64-bit unsigned integer (depending on the accelerator)
92 * whose Nth bit is set if and only if predicate evaluates to non-zero
93 * for the Nth thread of the warp and the Nth thread is active.
94 *
95 * It follows the logic of __ballot_sync(__activemask(), predicate) in CUDA.
96 *
97 * Note:
98 * * The programmer must ensure that all threads calling this function are executing
99 * the same line of code. In particular, it is not portable to write
100 * if(a) {ballot} else {ballot}.
101 *
102 * @param predicate The predicate value for current thread.
103 * @return bit mask where the Nth bit is set to 1 if the corresponding threads predicate was non zero. The return
104 * type can be 64bit or 32bit depending on the API.
105 */
106 template<alpaka::onAcc::concepts::Acc T_Acc>
107 constexpr auto ballot(T_Acc const& acc, int32_t predicate)
108 -> std::conditional_t<T_Acc::getWarpSize() <= 32u, uint32_t, uint64_t>
109 {
110 using Acc = ALPAKA_TYPEOF(acc);
111 using Api = ALPAKA_TYPEOF(acc[object::api]);
112 return internal::Ballot::Op<Acc, Api>{}(acc, Api{}, predicate);
113 }
114
115 /** Return the warp size.
116 *
117 * A warp is a collection of threads which work in lock step (executing the same command).
118 * The warp size can be larger than the number of threads executed in the kernel/ thread block.
119 * @{
120 */
121 template<concepts::Acc T_Acc>
122 constexpr uint32_t getSize()
123 {
125 }
126
127 template<concepts::Acc T_Acc>
128 constexpr uint32_t getSize(T_Acc const&)
129 {
130 return T_Acc::getWarpSize();
131 }
132
133 /** @} */
134
135 /** Exchange data between threads within a warp.
136 *
137 * Effectively executes:
138 *
139 * __shared__ int32_t values[warpsize];
140 * values[threadIdx.x] = value;
141 * __syncthreads();
142 * return values[width*(threadIdx.x/width) + srcLane%width];
143 *
144 * However, it does not use shared memory.
145 *
146 * Commonly used with width = warpsize (the default), (returns values[srcLane])
147 *
148 * This method supports to be called in diverging control flow branches if you only query values from threads
149 * within the same branch path.
150 *
151 * @param value value to broadcast, only used if other thread is addressing the lane of this thread.
152 * @param srcLane source lane index within the group range [0; width).
153 * @param width number of threads receiving a single value, must be a power of 2.
154 * @return val from the thread index srcLane.
155 */
156 template<typename T, alpaka::onAcc::concepts::Acc T_Acc>
157 requires(std::is_trivially_copyable_v<T>)
158 constexpr T shfl(T_Acc const& acc, T const& value, uint32_t srcLane, uint32_t width = getSize<T_Acc>())
159 {
160 using Acc = ALPAKA_TYPEOF(acc);
161 using Api = ALPAKA_TYPEOF(acc[object::api]);
162 return internal::Shfl::Op<Acc, Api, T>{}(acc, Api{}, value, srcLane, width != 0u ? width : getSize<T_Acc>());
163 }
164
165 /** Read data from threads with higher lane index within a warp.
166 *
167 * It copies from a lane with higher ID relative to caller.
168 * The lane ID is calculated by adding delta to the caller's lane ID.
169 *
170 * Effectively executes:
171 *
172 * __shared__ int32_t values[warpsize];
173 * values[threadIdx.x] = value;
174 * __syncthreads();
175 * return (threadIdx.x % width + delta < width) ? values[threadIdx.x + delta] : values[threadIdx.x];
176 *
177 * However, it does not use shared memory.
178 *
179 * Notes:
180 * * The programmer must ensure that all threads calling this
181 * function (and the srcLane) are executing the same line of code.
182 * In particular it is not portable to write if(a) {shfl} else {shfl}.
183 *
184 * * Commonly used with width = warpsize (the default), (returns values[threadIdx.x+delta] if threadIdx.x+delta <
185 * warpsize)
186 *
187 * @param value value to broadcast
188 * @param delta corresponds to the delta used to compute the lane ID
189 * @param width size of the group participating in the shuffle operation, must be a power of 2.
190 * @return the value from the thread index lane ID + delta within the group build by width, else value.
191 */
192 template<typename T, alpaka::onAcc::concepts::Acc T_Acc>
193 requires(std::is_trivially_copyable_v<T>)
194 constexpr T shflDown(T_Acc const& acc, T const& value, uint32_t delta, uint32_t width = getSize<T_Acc>())
195 {
196 using Acc = ALPAKA_TYPEOF(acc);
197 using Api = ALPAKA_TYPEOF(acc[object::api]);
198 return internal::ShflDown::Op<Acc, Api, T>{}(acc, Api{}, value, delta, width != 0u ? width : getSize<T_Acc>());
199 }
200
201 /** Read data from threads with lower lane index within a warp.
202 *
203 * It copies from a lane with lower ID relative to caller.
204 * The lane ID is calculated by subtracting delta from the caller's lane ID.
205 *
206 * Effectively executes:
207 *
208 * __shared__ int32_t values[warpsize];
209 * values[threadIdx.x] = value;
210 * __syncthreads();
211 * return (threadIdx.x % width >= delta) ? values[threadIdx.x - delta] : values[threadIdx.x];
212 *
213 * However, it does not use shared memory.
214 *
215 * Notes:
216 * * The programmer must ensure that all threads calling this
217 * function (and the srcLane) are executing the same line of code.
218 * In particular it is not portable to write if(a) {shfl} else {shfl}.
219 *
220 * Commonly used with width = warpsize (the default), (returns values[threadIdx.x - delta] if threadIdx.x >= delta)
221 *
222 * @param value value to broadcast
223 * @param delta corresponds to the delta used to compute the lane ID
224 * @param width size of the group participating in the shuffle operation, must be a power of 2.
225 * @return the value from the thread index lane ID + delta within the group build by width, else value.
226 */
227 template<typename T, alpaka::onAcc::concepts::Acc T_Acc>
228 requires(std::is_trivially_copyable_v<T>)
229 constexpr T shflUp(T_Acc const& acc, T const& value, uint32_t delta, uint32_t width = getSize<T_Acc>())
230 {
231 using Acc = ALPAKA_TYPEOF(acc);
232 using Api = ALPAKA_TYPEOF(acc[object::api]);
233 return internal::ShflUp::Op<Acc, Api, T>{}(acc, Api{}, value, delta, width != 0u ? width : getSize<T_Acc>());
234 }
235
236 /** Exchange data between threads within a warp.
237 *
238 * It copies from a lane based on bitwise XOR of own lane ID.
239 * The lane ID is calculated by performing a bitwise XOR of the caller's lane ID with laneMask
240 *
241 * Effectively executes:
242 *
243 * __shared__ int32_t values[warpsize];
244 * values[threadIdx.x] = value;
245 * __syncthreads();
246 * int lane = threadIdx.x ^ laneMask;
247 * return values[lane / width > threadIdx.x / width ? threadIdx.x : lane];
248 *
249 * However, it does not use shared memory.
250 *
251 * Notes:
252 * * The programmer must ensure that all threads calling this
253 * function (and the srcLane) are executing the same line of code.
254 * In particular it is not portable to write if(a) {shfl} else {shfl}.
255 *
256 * * Commonly used with width = warpsize (the default), (returns values[threadIdx.x^laneMask])
257 *
258 * * Width must be a power of 2.
259 * @param value value to broadcast
260 * @param laneMask mask applied to the thread lane index within the subgroup created by width.
261 * @param width size of the group participating in the shuffle operation, must be a power of 2.
262 * @return the value from the thread index lane ID
263 */
264 template<typename T, alpaka::onAcc::concepts::Acc T_Acc>
265 requires(std::is_trivially_copyable_v<T>)
266 constexpr T shflXor(T_Acc const& acc, T const& value, uint32_t laneMask, uint32_t width = getSize<T_Acc>())
267 {
268 using Acc = ALPAKA_TYPEOF(acc);
269 using Api = ALPAKA_TYPEOF(acc[object::api]);
271 acc,
272 Api{},
273 value,
274 laneMask,
275 width != 0u ? width : getSize<T_Acc>());
276 }
277} // namespace alpaka::onAcc::warp
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Definition common.hpp:154
Concept to check if a type is an accelerator.
Definition Acc.hpp:119
constexpr Api api
Definition tag.hpp:24
constexpr uint32_t getWarpIdx(alpaka::onAcc::concepts::Acc auto const &acc)
Return the warp index within the block.
Definition warp.hpp:81
constexpr uint32_t getSize()
Definition warp.hpp:27
constexpr uint32_t getLaneIdx(alpaka::onAcc::concepts::Acc auto const &acc)
Return the lane index of the current thread within its warp.
Definition warp.hpp:60
constexpr uint32_t getLaneIdx(alpaka::onAcc::concepts::Acc auto const &acc)
Return the lane index of the current thread within its warp.
Definition warp.hpp:41
constexpr bool any(alpaka::onAcc::concepts::Acc auto const &acc, int32_t predicate)
Evaluates predicate for all active threads of the warp.
Definition warp.hpp:83
constexpr T shflDown(T_Acc const &acc, T const &value, uint32_t delta, uint32_t width=getSize< T_Acc >())
Read data from threads with higher lane index within a warp.
Definition warp.hpp:194
constexpr T shfl(T_Acc const &acc, T const &value, uint32_t srcLane, uint32_t width=getSize< T_Acc >())
Exchange data between threads within a warp.
Definition warp.hpp:158
constexpr bool all(alpaka::onAcc::concepts::Acc auto const &acc, int32_t predicate)
Evaluates predicate for all active threads of the warp.
Definition warp.hpp:64
constexpr uint32_t getWarpIdx(alpaka::onAcc::concepts::Acc auto const &acc)
Return the warp index within the block.
Definition warp.hpp:47
constexpr T shflUp(T_Acc const &acc, T const &value, uint32_t delta, uint32_t width=getSize< T_Acc >())
Read data from threads with lower lane index within a warp.
Definition warp.hpp:229
constexpr auto ballot(T_Acc const &acc, int32_t predicate) -> std::conditional_t< T_Acc::getWarpSize()<=32u, uint32_t, uint64_t >
Evaluates predicate for all non-exited threads in a warp and returns a 32- or 64-bit unsigned integer...
Definition warp.hpp:107
constexpr auto activemask(T_Acc const &acc) -> std::conditional_t< T_Acc::getWarpSize()<=32u, uint32_t, uint64_t >
Return the bit-mask of active lanes for the warp associated with the accelerator.
Definition warp.hpp:33
constexpr uint32_t getSize()
Return the warp size.
Definition warp.hpp:122
constexpr T shflXor(T_Acc const &acc, T const &value, uint32_t laneMask, uint32_t width=getSize< T_Acc >())
Exchange data between threads within a warp.
Definition warp.hpp:266