xtensor
Loading...
Searching...
No Matches
xtensor_simd.hpp
1/***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
3 * Copyright (c) QuantStack *
4 * *
5 * Distributed under the terms of the BSD 3-Clause License. *
6 * *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9
10#ifndef XTENSOR_SIMD_HPP
11#define XTENSOR_SIMD_HPP
12
13#include <vector>
14
15#include <xtl/xdynamic_bitset.hpp>
16
17#include "xutils.hpp"
18
19#ifdef XTENSOR_USE_XSIMD
20
21#include <xsimd/xsimd.hpp>
22// #include <xsimd/memory/xsimd_load_store.hpp>
23
24#if defined(_MSV_VER) && (_MSV_VER < 1910)
25template <class T, class A>
26inline xsimd::batch_bool<T, A> isnan(const xsimd::batch<T, A>& b)
27{
28 return xsimd::isnan(b);
29}
30#endif
31
32namespace xt_simd
33{
34 template <class T, std::size_t A>
35 using aligned_allocator = xsimd::aligned_allocator<T, A>;
36
37 using aligned_mode = xsimd::aligned_mode;
38 using unaligned_mode = xsimd::unaligned_mode;
39
40 template <class A>
41 using allocator_alignment = xsimd::allocator_alignment<A>;
42
43 template <class A>
44 using allocator_alignment_t = xsimd::allocator_alignment_t<A>;
45
46 template <class C>
47 using container_alignment = xsimd::container_alignment<C>;
48
49 template <class C>
50 using container_alignment_t = xsimd::container_alignment_t<C>;
51
52 template <class T>
53 using simd_traits = xsimd::simd_traits<T>;
54
55 template <class T>
56 using revert_simd_traits = xsimd::revert_simd_traits<T>;
57
58 template <class T>
59 using simd_type = xsimd::simd_type<T>;
60
61 template <class T>
62 using simd_bool_type = xsimd::simd_bool_type<T>;
63
64 template <class T>
65 using revert_simd_type = xsimd::revert_simd_type<T>;
66
67 template <class T1, class T2>
68 using simd_return_type = xsimd::simd_return_type<T1, T2>;
69
70 using xsimd::broadcast_as;
71 using xsimd::get_alignment_offset;
72 using xsimd::load_as;
73 using xsimd::select;
74 using xsimd::store_as;
75
76 template <class V>
77 using is_batch_bool = xsimd::is_batch_bool<V>;
78
79 template <class V>
80 using is_batch_complex = xsimd::is_batch_complex<V>;
81
82 template <class T1, class T2>
83 using simd_condition = xsimd::detail::simd_condition<T1, T2>;
84}
85
86#else // XTENSOR_USE_XSIMD
87
88namespace xt_simd
89{
90 template <class T, std::size_t A>
92
94 {
95 };
96
98 {
99 };
100
101 template <class A>
103 {
104 using type = unaligned_mode;
105 };
106
107 template <class A>
108 using allocator_alignment_t = typename allocator_alignment<A>::type;
109
110 template <class C>
112 {
113 using type = unaligned_mode;
114 };
115
116 template <class C>
117 using container_alignment_t = typename container_alignment<C>::type;
118
119 template <class T>
121 {
122 using type = T;
123 using bool_type = bool;
124 using batch_bool = bool;
125 static constexpr std::size_t size = 1;
126 };
127
128 template <class T>
130 {
131 using type = T;
132 static constexpr std::size_t size = simd_traits<type>::size;
133 };
134
135 template <class T>
136 using simd_type = typename simd_traits<T>::type;
137
138 template <class T>
139 using simd_bool_type = typename simd_traits<T>::bool_type;
140
141 template <class T>
142 using revert_simd_type = typename revert_simd_traits<T>::type;
143
144 template <class R, class T>
145 inline simd_type<R> broadcast_as(const T& value)
146 {
147 return value;
148 }
149
150 template <class R, class T>
151 inline simd_type<R> load_as(const T* src, aligned_mode)
152 {
153 return *src;
154 }
155
156 template <class R, class T>
157 inline simd_type<R> load_as(const T* src, unaligned_mode)
158 {
159 return *src;
160 }
161
162 template <class R, class T>
163 inline void store_as(R* dst, const simd_type<T>& src, aligned_mode)
164 {
165 *dst = src;
166 }
167
168 template <class R, class T>
169 inline void store_as(R* dst, const simd_type<T>& src, unaligned_mode)
170 {
171 *dst = src;
172 }
173
174 template <class T>
175 inline T select(bool cond, const T& t1, const T& t2)
176 {
177 return cond ? t1 : t2;
178 }
179
180 template <class T>
181 inline std::size_t get_alignment_offset(const T* /*p*/, std::size_t size, std::size_t /*block_size*/)
182 {
183 return size;
184 }
185
186 template <class T1, class T2>
187 using simd_return_type = simd_type<T2>;
188
189 template <class V>
190 struct is_batch_bool : std::false_type
191 {
192 };
193
194 template <class V>
195 struct is_batch_complex : std::false_type
196 {
197 };
198
199 template <class T1, class T2>
200 struct simd_condition : std::true_type
201 {
202 };
203}
204
205#endif // XTENSOR_USE_XSIMD
206
207namespace xt
208{
211
213 {
214 };
215
216 namespace detail
217 {
218 template <class A1, class A2>
219 struct driven_align_mode_impl
220 {
221 using type = std::conditional_t<std::is_same<A1, A2>::value, A1, ::xt_simd::unaligned_mode>;
222 };
223
224 template <class A>
225 struct driven_align_mode_impl<inner_aligned_mode, A>
226 {
227 using type = A;
228 };
229 }
230
231 template <class A1, class A2>
233 {
234 using type = typename detail::driven_align_mode_impl<A1, A2>::type;
235 };
236
237 template <class A1, class A2>
238 using driven_align_mode_t = typename detail::driven_align_mode_impl<A1, A2>::type;
239
240 namespace detail
241 {
242 template <class E, class T, class = void>
243 struct has_load_simd : std::false_type
244 {
245 };
246
247 template <class E, class T>
248 struct has_load_simd<
249 E,
250 T,
251 void_t<decltype(std::declval<E>().template load_simd<aligned_mode, T>(typename E::size_type(0)))>>
252 : std::true_type
253 {
254 };
255
256 template <class E, class T, bool B = xt_simd::simd_condition<typename E::value_type, T>::value>
257 struct has_simd_interface_impl : has_load_simd<E, T>
258 {
259 };
260
261 template <class E, class T>
262 struct has_simd_interface_impl<E, T, false> : std::false_type
263 {
264 };
265 }
266
267 template <class E, class T = typename std::decay_t<E>::value_type>
268 struct has_simd_interface : detail::has_simd_interface_impl<E, T>
269 {
270 };
271
272 template <class T>
273 struct has_simd_type : std::integral_constant<bool, !std::is_same<T, xt_simd::simd_type<T>>::value>
274 {
275 };
276
277 namespace detail
278 {
279 template <class F, class B, class = void>
280 struct has_simd_apply_impl : std::false_type
281 {
282 };
283
284 template <class F, class B>
285 struct has_simd_apply_impl<F, B, void_t<decltype(&F::template simd_apply<B>)>> : std::true_type
286 {
287 };
288 }
289
290 template <class F, class B>
291 struct has_simd_apply : detail::has_simd_apply_impl<F, B>
292 {
293 };
294
295 template <class T>
296 using bool_load_type = std::conditional_t<std::is_same<T, bool>::value, uint8_t, T>;
297
298 template <class T>
299 struct forbid_simd : std::false_type
300 {
301 };
302
303 template <class A>
304 struct forbid_simd<std::vector<bool, A>> : std::true_type
305 {
306 };
307
308 template <class A>
309 struct forbid_simd<const std::vector<bool, A>> : std::true_type
310 {
311 };
312
313 template <class B, class A>
314 struct forbid_simd<xtl::xdynamic_bitset<B, A>> : std::true_type
315 {
316 };
317
318 template <class B, class A>
319 struct forbid_simd<const xtl::xdynamic_bitset<B, A>> : std::true_type
320 {
321 };
322
323 template <class C, class T1, class T2>
325 : std::enable_if<!forbid_simd<C>::value, xt_simd::simd_return_type<T1, bool_load_type<T2>>>
326 {
327 };
328
329 template <class C, class T1, class T2>
330 using container_simd_return_type_t = typename container_simd_return_type<C, T1, T2>::type;
331}
332
333#endif
standard mathematical functions for xexpressions