alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
EmuSimd.hpp
Go to the documentation of this file.
1/* Copyright 2025 René Widera
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5/** @file This file provides a basic implementation of a SIMD vector.
6 *
7 * The implementation is based on the class Vec:
8 * - the storge policy should become the native SIMD implementation e.g. std::simd
9 * - load/ store and simd specifis should be implemented in the storage policy
10 * - the name of storage policy should be changed
11 *
12 * The current operator operations relay on compilers auto vectorization.
13 */
14
15#pragma once
16
17#include "alpaka/api/api.hpp"
22#include "alpaka/simd/trait.hpp"
23
24#include <concepts>
25#include <type_traits>
26
27namespace alpaka
28{
29 namespace internal
30 {
31 /** Simd array storge for vector data
32 *
33 * The storage is aligned for native simd usage.
34 */
35 template<typename T_Type, uint32_t T_width>
36 struct alignas(alpaka::internal::optimalAlignment<T_Type, T_width, Alignment<sizeof(T_Type) * T_width>>())
37 EmuSimd : protected std::array<T_Type, T_width>
38 {
39 using BaseType = std::array<T_Type, T_width>;
40
41 using value_type = typename BaseType::value_type;
42 using reference = typename BaseType::reference;
43
44 using BaseType::operator[];
45
46 constexpr EmuSimd() = default;
47
48 constexpr EmuSimd(EmuSimd const& other)
49 {
50 // attention: using default constructor results in bad performance
51 for(uint32_t i = 0u; i < T_width; ++i)
52 BaseType::operator[](i) = other[i];
53 }
54
55 constexpr EmuSimd(EmuSimd&&) = default;
56 constexpr EmuSimd& operator=(EmuSimd&& rhs) = default;
57
58 constexpr EmuSimd& operator=(EmuSimd const& rhs) = default;
59
60 constexpr EmuSimd& operator=(T_Type const value)
61 {
62 for(uint32_t i = 0u; i < T_width; i++)
63 {
64 asNativeType()[i] = value;
65 }
66 return *this;
67 }
68
69 // constructor is required because exposing the array constructors does not work
70 template<typename... T_Args>
71 requires(sizeof...(T_Args) == T_width && (std::same_as<T_Args, T_Type> && ...))
72 constexpr EmuSimd(T_Args&&... args) : BaseType{std::forward<T_Args>(args)...}
73 {
74 }
75
76 constexpr EmuSimd(BaseType const& base) : BaseType{base}
77 {
78 }
79
80 /** static cast the instance to the parent class
81 *
82 * This method is mostly used to get access to native arithmetic and comparison operators.
83 * @{
84 */
85 constexpr auto& asNativeType()
86 {
87 return static_cast<EmuSimd&>(*this);
88 }
89
90 constexpr auto const& asNativeType() const
91 {
92 return static_cast<EmuSimd const&>(*this);
93 }
94
95 /** @} */
96
97 static constexpr auto fill(T_Type value)
98 {
99 return EmuSimd([&value](uint32_t const) { return value; });
100 }
101
102 template<typename F>
103 requires(std::is_invocable_v<F, std::integral_constant<uint32_t, 0u>>)
104 constexpr explicit EmuSimd(F&& generator)
105 : EmuSimd(std::forward<F>(generator), std::make_integer_sequence<uint32_t, T_width>{})
106 {
107 }
108
109 constexpr void copyFrom(T_Type const* data, alpaka::concepts::Alignment auto alignment)
110 {
111 if constexpr((alignment.template get<T_Type>() % alignof(ALPAKA_TYPEOF(*this))) == 0u)
112 *(this) = *reinterpret_cast<ALPAKA_TYPEOF(*this) const*>(data);
113 else
114 {
115 for(uint32_t i = 0u; i < T_width; ++i)
116 asNativeType()[i] = data[i];
117 }
118 }
119
120 constexpr void copyTo(auto* data, alpaka::concepts::Alignment auto alignment) const
121 {
122 if constexpr((alignment.template get<T_Type>() % alignof(ALPAKA_TYPEOF(*this))) == 0u)
123 *reinterpret_cast<std::remove_const_t<ALPAKA_TYPEOF(*this)>*>(data) = (*this);
124 else
125 {
126 for(uint32_t i = 0u; i < T_width; ++i)
127 data[i] = asNativeType()[i];
128 }
129 }
130
131 template<alpaka::concepts::SimdMask Mask, alpaka::concepts::Simd T_Simd>
132 friend struct SimdWhereExpr;
133
134 /** element wise conditional value update where t is a scalar */
135 constexpr void update(alpaka::concepts::SimdMask auto const& mask, alpaka::concepts::Simd auto const& t)
136 {
137 using MaskType = ALPAKA_TYPEOF(valueMaskCast<T_Type>(t[0]));
138 if constexpr(std::same_as<MaskType, bool>)
139 {
140 for(uint32_t i = 0u; i < T_width; ++i)
141 asNativeType()[i] = (mask[i] ? t[i] : asNativeType()[i]);
142 }
143 else
144 {
145 for(uint32_t i = 0u; i < T_width; ++i)
146 asNativeType()[i] = std::bit_cast<T_Type>(
147 (mask.asNativeType()[i] & std::bit_cast<MaskType>(t[i]))
148 | (~mask.asNativeType()[i] & std::bit_cast<MaskType>(asNativeType()[i])));
149 }
150 }
151
152 /** element wise conditional value update where t is a scalar */
153 constexpr void update(alpaka::concepts::SimdMask auto const& mask, T_Type const& t)
154 {
155 using MaskType = ALPAKA_TYPEOF(valueMaskCast<T_Type>(t));
156 if constexpr(std::same_as<MaskType, bool>)
157 {
158 for(uint32_t i = 0u; i < T_width; ++i)
159 asNativeType()[i] = (mask[i] ? t : asNativeType()[i]);
160 }
161 else
162 {
163 for(uint32_t i = 0u; i < T_width; ++i)
164 asNativeType()[i] = std::bit_cast<T_Type>(
165 (mask.asNativeType()[i] & std::bit_cast<MaskType>(t))
166 | (~mask.asNativeType()[i] & std::bit_cast<MaskType>(asNativeType()[i])));
167 }
168 }
169
170 /** assign operator
171 */
172#define ALPAKA_VECTOR_ASSIGN_OP(op) \
173 constexpr EmuSimd& operator op(EmuSimd const& rhs) \
174 { \
175 for(uint32_t i = 0u; i < T_width; i++) \
176 { \
177 asNativeType()[i] op rhs[i]; \
178 } \
179 return *this; \
180 } \
181 constexpr EmuSimd& operator op(T_Type const value) \
182 { \
183 for(uint32_t i = 0u; i < T_width; i++) \
184 { \
185 asNativeType()[i] op value; \
186 } \
187 return *this; \
188 }
189
194
195#undef ALPAKA_VECTOR_ASSIGN_OP
196
197 private:
198 template<typename F, uint32_t... Is>
199 constexpr explicit EmuSimd(F&& generator, std::integer_sequence<uint32_t, Is...>)
200 : BaseType{generator(std::integral_constant<uint32_t, Is>{})...}
201 {
202 }
203 };
204
205#define ALPAKA_VECTOR_BINARY_OP(typenameOrConcept, op) \
206 template<typenameOrConcept T_Type, uint32_t T_width> \
207 constexpr auto operator op(const EmuSimd<T_Type, T_width>& lhs, const EmuSimd<T_Type, T_width>& rhs) \
208 { \
209 EmuSimd<T_Type, T_width> ret{}; \
210 for(uint32_t i = 0u; i < T_width; i++) \
211 ret[i] = lhs[i] op rhs[i]; \
212 return ret; \
213 } \
214 template<typenameOrConcept T_Type, uint32_t T_width> \
215 constexpr auto operator op(const EmuSimd<T_Type, T_width>& lhs, T_Type rhs) \
216 { \
217 EmuSimd<T_Type, T_width> ret{}; \
218 for(uint32_t i = 0u; i < T_width; i++) \
219 ret[i] = lhs[i] op rhs; \
220 return ret; \
221 } \
222 template<typenameOrConcept T_Type, uint32_t T_width> \
223 constexpr auto operator op(T_Type lhs, const EmuSimd<T_Type, T_width>& rhs) \
224 { \
225 EmuSimd<T_Type, T_width> ret{}; \
226 for(uint32_t i = 0u; i < T_width; i++) \
227 ret[i] = lhs op rhs[i]; \
228 return ret; \
229 }
230
231 ALPAKA_VECTOR_BINARY_OP(typename, +)
232 ALPAKA_VECTOR_BINARY_OP(typename, -)
233 ALPAKA_VECTOR_BINARY_OP(typename, *)
234 ALPAKA_VECTOR_BINARY_OP(typename, /)
235 ALPAKA_VECTOR_BINARY_OP(std::integral, %)
236 ALPAKA_VECTOR_BINARY_OP(std::integral, <<)
237 ALPAKA_VECTOR_BINARY_OP(std::integral, >>)
238 ALPAKA_VECTOR_BINARY_OP(std::integral, &)
239 ALPAKA_VECTOR_BINARY_OP(std::integral, |)
240 ALPAKA_VECTOR_BINARY_OP(std::integral, ^)
241
242#undef ALPAKA_VECTOR_BINARY_OP
243
244 } // namespace internal
245
246 namespace trait
247 {
248 template<concepts::Api T_Api, typename T_Type, uint32_t T_width>
250 {
251 using type = internal::EmuSimd<T_Type, T_width>;
252 };
253 } // namespace trait
254} // namespace alpaka
#define ALPAKA_VECTOR_ASSIGN_OP(op)
assign operator
Definition Simd.hpp:232
#define ALPAKA_VECTOR_BINARY_OP(typenameOrConcept, op)
binary operators
Definition Simd.hpp:549
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Definition common.hpp:153
decltype(auto) data(auto &&any)
pointer to data of an object
main alpaka namespace.
Definition alpaka.hpp:76
constexpr decltype(auto) get(concepts::SpecializationOf< Dict > auto &t) noexcept
Definition Dict.hpp:151
STL namespace.
Get the storage type for a SIMD pack.
Definition EmuSimd.hpp:250
internal::EmuSimd< T_Type, T_width > type
Definition EmuSimd.hpp:251