alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
fn.hpp
Go to the documentation of this file.
1/* Copyright 2026 René Widera
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5#pragma once
7#include "alpaka/concepts.hpp"
9#include "alpaka/tag.hpp"
10
11#include <type_traits>
12
13/** @brief alpaka'S function interface
14 *
15 * This file defines the interface for registering, dispatching and calling function overloads specialize for device
16 * specifications. A device specification consists of an alpaka API and device kind. These functions can be dispatched
17 * to third-party libraries (e.g. cuBLAS) and can be used in alpaka onHost or onAcc. The function interface of alpaka
18 * provides a way to work natively with alpaka objects while being able to use third party interfaces for functionality
19 * not provided in alpaka or in cases where the vendor implementation provides better performance. For each exposed
20 * function you can provide a fallback to an alpaka implementation for a device specification or a device specification
21 * independent generic implementation. This keeps your code base portable even if you can not dispatch to a third
22 * party/vendor library and avoids preprocessor macros around function calls. The preprocessor macro ALPAKA_FN_SYMBOL()
23 * should be used to declare a function symbol.
24 * A function symbol follows all requirements to be used as kernel within alpaka.
25 *
26 * The main components of the interface are:
27 * - `alpaka::fn::Fn`: The function symbol baseclass that can be used to register, dispatch and call third party
28 * functions.
29 * - `alpakaFnRegister`: A function template that can be specialized to register a function overload for a
30 * device specification. This is optional and only required if Registration::enforced is set to the function
31 * symbol. It allows the usage of isRegistered() function to check if a third party function overload is defined.
32 * - `alpakaFnDispatch`: A function template that can be specialized to dispatch a function symbol to a third party
33 * function depending on the device specification.
34 *
35 * For an example of how to use the interface see example/vendorApi.
36 */
37namespace alpaka::fn
38{
39 namespace api
40 {
41 /** @brief Api tag for alpaka.
42 *
43 * @warning This api should be used together with alpaka's function interface, it is not compatible with other
44 * alpaka interfaces where api's are required.
45 */
47 {
49
50 auto get() const
51 {
52 return this;
53 }
54
55 void _()
56 {
57 static_assert(concepts::Api<Alpaka>);
58 }
59
60 static std::string getName()
61 {
62 return "Alpaka";
63 }
64 };
65
66 constexpr auto alpaka = Alpaka{};
67 } // namespace api
68
69 /** @brief Fallback policy for function calls.
70 *
71 * This enum defines the fallback policy for function calls. It is used as a template parameter in
72 * `alpaka::fn::Fn` or ALPAKA_FN_SYMBOL to specify the fallback behavior if no vendor function overload is defined
73 * for the given device specification.
74 */
75 enum class Fallback : int
76 {
77 /** The generic implementation is called if no other overload fits.
78 *
79 * Should be used to ensure portability between different heterogeneous APIs.
80 */
82 /** The alpaka implementation is called if no other overload fits.
83 *
84 * Should be used to ensure portability between different heterogeneous APIs.
85 */
87 /** No fallback is performed in case no overload is fitting.
88 *
89 * Should be used if you want to ensure that a third party function overload is guaranteed to be called.
90 */
91 none = 3
92 };
93
94 /** @brief Policy to control if a function symbol must be registered.
95 */
96 enum class Registration : int
97 {
98 /** The isRegistered() function will always return true. This can be used to skip the registration of the
99 * function symbol via alpakaFnRegister().
100 */
102 /** It is required to define alpakaFnRegister() for a function symbol. isRegistered() can be called to check if
103 * a vendor function overload is registered for the given device specification.
104 */
106 /** The isRegistered() function is not available and no registration of the vendor function overloads is
107 * required. This can be used if you do not want to use the isRegistered() function and do not want to require
108 * the definition of alpakaFnRegister() for a function symbol.
109 */
111 };
112
113 namespace concepts
114 {
115 /** @brief Concept to check if a function symbol can be called.
116 *
117 * This concept checks if the alpakaFnDispatch() can be called with the given function symbol (if
118 * Fallback::toGeneric) or function symbol device specification. It is used to check if a function dispatch is
119 * defined for the given device specification or function symbol and if it can be called with the given
120 * arguments.
121 */
122 template<typename T_FnSpec, typename... Args>
124 = requires(T_FnSpec fnSpec, Args&&... args) { alpakaFnDispatch(fnSpec, std::forward<Args>(args)...); };
125
126 /** @brief Concept to check if a function symbol is registered.
127 *
128 * This concept checks if the alpakaFnRegister() can be called with the given function symbol or
129 * function symbol device specification. It is used to check if a vendor function overload is defined for the
130 * given device specification without taking any function arguments into account.
131 */
132 template<typename T_FnSpec>
133 concept FnRegistered = requires(T_FnSpec fnSpec) { alpakaFnRegister(fnSpec); };
134 } // namespace concepts
135
136 /** @brief Base class for function symbols.
137 *
138 * @tparam T_FnClass The function symbol to register, dispatch and call. The class should be trivially
139 * constructable. By using the static call() function or the operator()
140 * @tparam T_fallbackPolicy The fallback policy if no vendor function overload is defined for the given device
141 * specification. If set to Fallback::toAlpaka the alpaka implementation is called if no other overload fits. If
142 * set to Fallback::none no fallback is performed and a static assert is triggered if no function overload is
143 * defined for the given device specification.
144 * @tparam T_registrationPolicy If set to Registration::enforced the isRegistered() can be called, and it is
145 * required to define alpakaFnRegister() for on T_FnClass. If set to Registration::none the isRegistered()
146 * function is not available and no registration of the vendor function overloads is required. If set to
147 * Registration::alwaysTrue isRegistered() will always return true. This can be used to skip the registration
148 * of the function symbol.
149 */
150 template<
151 typename T_FnClass,
152 Fallback T_fallbackPolicy = Fallback::toGeneric,
153 Registration T_registrationPolicy = Registration::none>
154 struct Fn
155 {
156 /** Get the function specification.
157 *
158 * @return the function specification for the given entity.
159 *
160 * @{
161 */
162 static constexpr auto spec(alpaka::concepts::DeviceSpec auto const& any)
163 {
164 return spec(getApi(any), getDeviceKind(any));
165 }
166
167 template<alpaka::concepts::Api T_Api, alpaka::concepts::DeviceKind T_DeviceKind>
168 static constexpr auto spec(T_Api api, T_DeviceKind deviceKind)
169 {
170 alpaka::unused(api, deviceKind);
171 return typename T_FnClass::template Spec<T_Api, T_DeviceKind>{};
172 }
173
174 /** @} */
175
176 /** Checks if a function overload is registered for the given device specification.
177 *
178 * You can use the result to optionally call the function overload and disable at compile time code sections
179 * similar to C++ preprocessor guards.
180 * @code
181 * ALPAKA_FN_SYMBOL(Foo,alpaka::fn::Fallback::none, alpaka::fn::Registration::enforced);
182 *
183 * void alpakaFnRegister(Foo::Spec<alpaka::api::Host, alpaka::deviceKind::Cpu>)
184 * {
185 * }
186 *
187 * if constexpr (Foo::isRegistered(queue))
188 * {
189 * // more code
190 * Foo::call(queue,args ...);
191 * // more code
192 * }
193 * @endcode
194 *
195 * @param any any type which is usable with alpaka::getApi() and alpaka::getDeviceKind()
196 * @return true if the function overload T_FnClass is registered else false.
197 * It does not try to check if a fallback overload is dispatchable, to check fallback registrations use
198 * hasRegisteredFallback(alpaka::concepts::DeviceSpec auto const& any).
199 */
200 static constexpr bool isRegistered(alpaka::concepts::DeviceSpec auto const& any)
201 requires(T_registrationPolicy != Registration::none)
202 {
203 return T_registrationPolicy == Registration::alwaysTrue
205 }
206
207 /** Checks if the function overload fallback is registered.
208 *
209 * Similar to isRegistered(alpaka::concepts::DeviceSpec auto const& any) but it checks for the fallback
210 * overload only.
211 *
212 * @param any any type which is usable with alpaka::getApi() and alpaka::getDeviceKind()
213 * @return true if the function overload fallback for T_FnClass is registered else false.
214 */
215 static constexpr bool hasRegisteredFallback(alpaka::concepts::DeviceSpec auto const& any)
216 requires(T_registrationPolicy != Registration::none)
217 {
218 constexpr bool isFallbackAllowed = T_fallbackPolicy != Fallback::none;
219 constexpr bool hasAlpakaFallback
220 = ((T_fallbackPolicy == Fallback::toAlpaka)
222 constexpr bool hasGenericFallback
223 = ((T_fallbackPolicy == Fallback::toGeneric) && concepts::FnRegistered<T_FnClass>);
224 return T_registrationPolicy == Registration::alwaysTrue
225 || (isFallbackAllowed && (hasAlpakaFallback || hasGenericFallback));
226 }
227
228 /** Call function overload if defined for the given device specification. */
229 template<alpaka::concepts::DeviceSpec T_Any, typename... Args>
231 constexpr decltype(auto) operator()(T_Any&& any, Args&&... args) const
232 {
233 static_assert(
234 T_registrationPolicy != Registration::enforced || concepts::FnRegistered<ALPAKA_TYPEOF(spec(any))>,
235 "Function dispatch for the given function symbol, API and device kind is not registered.");
236 return alpakaFnDispatch(spec(any), std::forward<T_Any>(any), std::forward<Args>(args)...);
237 }
238
239 /** Fallback operator() to alpaka implementation if the function is not dispatchable for the given device
240 * specification.
241 *
242 * This operator() is only enabled if T_fallbackPolicy is set to toAlpaka and function is
243 * dispatchable for the given device specification.
244 */
245 template<alpaka::concepts::DeviceSpec T_Any, typename... Args>
246 requires(
248 && (T_fallbackPolicy == Fallback::toAlpaka))
249 constexpr decltype(auto) operator()(T_Any&& any, Args&&... args) const
250 {
251 static_assert(
252 T_registrationPolicy != Registration::enforced
254 "Function for the given function group, device kind the api fn::api::alpaka is not registered.");
255 return alpakaFnDispatch(
257 std::forward<T_Any>(any),
258 std::forward<Args>(args)...);
259 }
260
261 /** Fallback operator() to generic function if not dispatchable for the given device
262 * specification.
263 *
264 * This operator() is only enabled if T_fallbackPolicy is set toGeneric and function is
265 * dispatchable without a device specification.
266 */
267 template<alpaka::concepts::DeviceSpec T_Any, typename... Args>
268 requires(
269 // no dispatch with device specification
271 // generic function dispatchable
272 concepts::DispatchedFnInvocable<T_FnClass, T_Any, Args...> && (T_fallbackPolicy == Fallback::toGeneric))
273 constexpr decltype(auto) operator()(T_Any&& any, Args&&... args) const
274 {
275 static_assert(
277 "Function dispatch for the given function symbol, is not registered.");
278 return alpakaFnDispatch(T_FnClass{}, std::forward<T_Any>(any), std::forward<Args>(args)...);
279 }
280
281 /** Call the function overload for the given device specification.
282 *
283 * See the call operator().
284 * @attention call() is a static function where the call operator required an instance of this class.
285 */
286 static constexpr decltype(auto) call(alpaka::concepts::DeviceSpec auto&& any, auto&&... args)
287 {
288 static_assert(
289 std::is_trivially_constructible_v<T_FnClass>,
290 "Function class must be trivially constructible to use call().");
291 return T_FnClass{}(ALPAKA_FORWARD(any), ALPAKA_FORWARD(args)...);
292 }
293 };
294} // namespace alpaka::fn
295
296/** @brief Define a function symbol class for alpaka's function interface
297 *
298 * @param fnName Name of the function symbol. This can be used to call the function overloads with the static
299 * call() function without having to create an instance or with the operator().
300 * @param optional_fallback The fallback policy if no vendor function overload is defined for the given device
301 * specification. If set to Fallback::toAlpaka the generic alpaka implementation is called if no other overload is
302 * fitting. If set to Fallback::toGeneric the overload with the function symbol as first argument is called if no other
303 * function device specification is callable. If set to Fallback::none no fallback is performed and a static assert is
304 * triggered if no vendor function overload is defined for the given device specification. Default:
305 * Fallback::toGeneric.
306 * @param optional_registartion If set to Registration::enforced the isRegistered() can be called, and it is
307 * required to define alpakaFnRegister() for on T_FnClass. If set to Registration::none the isRegistered()
308 * function is not available and no registration of the vendor function overloads is required. If set to
309 * Registration::alwaysTrue isRegistered() will always return true. This can be used to skip the registration of
310 * the function symbol. Default: Registration::none.
311 *
312 * @code
313 * ALPAKA_FN_SYMBOL(Transform, alpaka::fn::Fallback::toAlpaka, alpaka::fn::Registration::enforced);
314 * ALPAKA_FN_SYMBOL(TransformWithFallback, alpaka::fn::Fallback::toAlpaka);
315 * ALPAKA_FN_SYMBOL(TransformWithFallbackAndRegistration, alpaka::fn::Fallback::toGeneric,
316 * alpaka::fn::Registration::enforced);
317 * @endcode
318 */
319#define ALPAKA_FN_SYMBOL(fnName, ...) \
320 struct fnName : alpaka::fn::Fn<fnName __VA_OPT__(, __VA_ARGS__)> \
321 { \
322 /** Function specification for a given device specification. \
323 * \
324 * This struct should be specialized for each device specification combination where a vendor \
325 * function overload is defined. The specialization should be empty and only used as a tag to \
326 * identify the function overload. \
327 */ \
328 template<alpaka::concepts::Api T_Api, alpaka::concepts::DeviceKind T_DeviceKind> \
329 struct Spec \
330 { \
331 }; \
332 }; \
333 static_assert(true)
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Definition common.hpp:154
#define ALPAKA_FORWARD(instance)
Perfectly forward an instance as argument.
Definition common.hpp:148
Concept to check for APIs.
Definition api.hpp:42
Concept to check that a device specification with an API and device kind can be extracted.
Definition concepts.hpp:58
Concept to check if a function symbol can be called.
Definition fn.hpp:124
Concept to check if a function symbol is registered.
Definition fn.hpp:133
alpaka'S function interface
Definition fn.hpp:38
Fallback
Fallback policy for function calls.
Definition fn.hpp:76
@ none
No fallback is performed in case no overload is fitting.
Definition fn.hpp:91
@ toAlpaka
The alpaka implementation is called if no other overload fits.
Definition fn.hpp:86
@ toGeneric
The generic implementation is called if no other overload fits.
Definition fn.hpp:81
Registration
Policy to control if a function symbol must be registered.
Definition fn.hpp:97
@ none
The isRegistered() function is not available and no registration of the vendor function overloads is ...
Definition fn.hpp:110
@ enforced
It is required to define alpakaFnRegister() for a function symbol.
Definition fn.hpp:105
@ alwaysTrue
The isRegistered() function will always return true.
Definition fn.hpp:101
main alpaka namespace.
Definition alpaka.hpp:76
constexpr decltype(auto) getDeviceKind(auto &&any)
Get the device type of an object.
Definition interface.hpp:78
constexpr decltype(auto) getApi(auto &&any)
Get the API an object depends on.
Definition interface.hpp:42
Base class for function symbols.
Definition fn.hpp:155
static constexpr bool hasRegisteredFallback(alpaka::concepts::DeviceSpec auto const &any)
Checks if the function overload fallback is registered.
Definition fn.hpp:215
static constexpr bool isRegistered(alpaka::concepts::DeviceSpec auto const &any)
Checks if a function overload is registered for the given device specification.
Definition fn.hpp:200
static constexpr auto spec(alpaka::concepts::DeviceSpec auto const &any)
Get the function specification.
Definition fn.hpp:162
static constexpr decltype(auto) call(alpaka::concepts::DeviceSpec auto &&any, auto &&... args)
Call the function overload for the given device specification.
Definition fn.hpp:286
static constexpr auto spec(T_Api api, T_DeviceKind deviceKind)
Get the function specification.
Definition fn.hpp:168
Api tag for alpaka.
Definition fn.hpp:47
static std::string getName()
Definition fn.hpp:60
auto get() const
Definition fn.hpp:50