25#ifndef _GLIBCXX_SIMD_LOADSTORE_H
26#define _GLIBCXX_SIMD_LOADSTORE_H 1
29#pragma GCC system_header
32#if __cplusplus >= 202400L
37#pragma GCC diagnostic push
38#pragma GCC diagnostic ignored "-Wpsabi"
41namespace std _GLIBCXX_VISIBILITY(default)
43_GLIBCXX_BEGIN_NAMESPACE_VERSION
46 template <
typename _Vp,
typename _Tp>
47 struct __vec_load_return
48 {
using type = _Vp; };
50 template <
typename _Tp>
51 struct __vec_load_return<void, _Tp>
52 {
using type = basic_vec<_Tp>; };
54 template <
typename _Vp,
typename _Tp>
55 using __vec_load_return_t =
typename __vec_load_return<_Vp, _Tp>::type;
57 template <
typename _Vp,
typename _Tp>
58 using __load_mask_type_t =
typename __vec_load_return_t<_Vp, _Tp>::mask_type;
60 template <
typename _Tp>
61 concept __sized_contiguous_range
62 = ranges::contiguous_range<_Tp> && ranges::sized_range<_Tp>;
64 template <
typename _Vp = void, __sized_contiguous_range _Rg,
typename... _Flags>
65 [[__gnu__::__always_inline__]]
66 constexpr __vec_load_return_t<_Vp, ranges::range_value_t<_Rg>>
67 unchecked_load(_Rg&& __r, flags<_Flags...> __f = {})
69 using _Tp = ranges::range_value_t<_Rg>;
70 using _RV = __vec_load_return_t<_Vp, _Tp>;
71 using _Rp =
typename _RV::value_type;
72 static_assert(__loadstore_convertible_to<ranges::range_value_t<_Rg>, _Rp, _Flags...>,
73 "'flag_convert' must be used for conversions that are not value-preserving");
75 constexpr bool __allow_out_of_bounds = __f._S_test(__allow_partial_loadstore);
76 constexpr size_t __static_size = __static_range_size(__r);
78 if constexpr (!__allow_out_of_bounds && ranges::__static_sized_range<_Rg>)
79 static_assert(ranges::size(__r) >= _RV::size(),
"given range must have sufficient size");
81 const auto* __ptr = __f.template _S_adjust_pointer<_RV>(ranges::data(__r));
82 const auto __rg_size = std::ranges::size(__r);
83 if constexpr (!__allow_out_of_bounds)
84 __glibcxx_simd_precondition(
85 std::ranges::size(__r) >= _RV::size(),
86 "Input range is too small. Did you mean to use 'partial_load'?");
90 return _RV([&](
size_t __i) -> _Rp {
93 else if constexpr (__complex_like<_Rp> && !__complex_like<_Tp>)
94 return static_cast<typename _Rp::value_type
>(__r[__i]);
96 return static_cast<_Rp
>(__r[__i]);
101 if constexpr ((__static_size != dynamic_extent && __static_size >= size_t(_RV::size()))
102 || !__allow_out_of_bounds)
103 return _RV(_LoadCtorTag(), __ptr);
105 return _RV::_S_partial_load(__ptr, __rg_size);
109 template <
typename _Vp = void, __sized_contiguous_range _Rg,
typename... _Flags>
110 [[__gnu__::__always_inline__]]
111 constexpr __vec_load_return_t<_Vp, ranges::range_value_t<_Rg>>
112 unchecked_load(_Rg&& __r,
const __load_mask_type_t<_Vp, ranges::range_value_t<_Rg>>& __mask,
113 flags<_Flags...> __f = {})
115 using _Tp = ranges::range_value_t<_Rg>;
116 using _RV = __vec_load_return_t<_Vp, _Tp>;
117 using _Rp =
typename _RV::value_type;
118 static_assert(__vectorizable<_Tp>);
119 static_assert(__explicitly_convertible_to<_Tp, _Rp>);
120 static_assert(__loadstore_convertible_to<_Tp, _Rp, _Flags...>,
121 "'flag_convert' must be used for conversions that are not value-preserving");
123 constexpr bool __allow_out_of_bounds = __f._S_test(__allow_partial_loadstore);
124 constexpr auto __static_size = __static_range_size(__r);
126 if constexpr (!__allow_out_of_bounds && ranges::__static_sized_range<_Rg>)
127 static_assert(ranges::size(__r) >= _RV::size(),
"given range must have sufficient size");
129 const auto* __ptr = __f.template _S_adjust_pointer<_RV>(ranges::data(__r));
131 if constexpr (!__allow_out_of_bounds)
132 __glibcxx_simd_precondition(
133 ranges::size(__r) >=
size_t(_RV::size()),
134 "Input range is too small. Did you mean to use 'partial_load'?");
136 const size_t __rg_size = ranges::size(__r);
139 return _RV([&](
size_t __i) -> _Rp {
140 if (__i >= __rg_size || !__mask[
int(__i)])
142 else if constexpr (__complex_like<_Rp> && !__complex_like<_Tp>)
143 return static_cast<typename _Rp::value_type
>(__r[__i]);
145 return static_cast<_Rp
>(__r[__i]);
150 constexpr bool __no_size_check
151 = !__allow_out_of_bounds
152 || (__static_size != dynamic_extent
153 && __static_size >= size_t(_RV::size.value));
154 if constexpr (_RV::size() == 1)
155 return __mask[0] && (__no_size_check || __rg_size > 0) ? _RV(_LoadCtorTag(), __ptr)
157 else if constexpr (__no_size_check)
158 return _RV::_S_masked_load(__ptr, __mask);
159 else if (__rg_size >=
size_t(_RV::size()))
160 return _RV::_S_masked_load(__ptr, __mask);
161 else if (__rg_size > 0)
162 return _RV::_S_masked_load(
163 __ptr, __mask && _RV::mask_type::_S_partial_mask_of_n(
int(__rg_size)));
169 template <
typename _Vp = void, contiguous_iterator _It,
typename... _Flags>
170 [[__gnu__::__always_inline__]]
171 constexpr __vec_load_return_t<_Vp, iter_value_t<_It>>
172 unchecked_load(_It __first, iter_difference_t<_It> __n, flags<_Flags...> __f = {})
173 {
return simd::unchecked_load<_Vp>(span<
const iter_value_t<_It>>(__first, __n), __f); }
175 template <
typename _Vp = void, contiguous_iterator _It,
typename... _Flags>
176 [[__gnu__::__always_inline__]]
177 constexpr __vec_load_return_t<_Vp, iter_value_t<_It>>
178 unchecked_load(_It __first, iter_difference_t<_It> __n,
179 const __load_mask_type_t<_Vp, iter_value_t<_It>>& __mask,
180 flags<_Flags...> __f = {})
181 {
return simd::unchecked_load<_Vp>(span<
const iter_value_t<_It>>(__first, __n), __mask, __f); }
183 template <
typename _Vp =
void, contiguous_iterator _It, sized_sentinel_for<_It> _Sp,
185 [[__gnu__::__always_inline__]]
186 constexpr __vec_load_return_t<_Vp, iter_value_t<_It>>
187 unchecked_load(_It __first, _Sp __last, flags<_Flags...> __f = {})
188 {
return simd::unchecked_load<_Vp>(span<
const iter_value_t<_It>>(__first, __last), __f); }
190 template <
typename _Vp =
void, contiguous_iterator _It, sized_sentinel_for<_It> _Sp,
192 [[__gnu__::__always_inline__]]
193 constexpr __vec_load_return_t<_Vp, iter_value_t<_It>>
194 unchecked_load(_It __first, _Sp __last,
195 const __load_mask_type_t<_Vp, iter_value_t<_It>>& __mask,
196 flags<_Flags...> __f = {})
198 return simd::unchecked_load<_Vp>(span<
const iter_value_t<_It>>(__first, __last), __mask, __f);
201 template <
typename _Vp = void, __sized_contiguous_range _Rg,
typename... _Flags>
202 [[__gnu__::__always_inline__]]
203 constexpr __vec_load_return_t<_Vp, ranges::range_value_t<_Rg>>
204 partial_load(_Rg&& __r, flags<_Flags...> __f = {})
205 {
return simd::unchecked_load<_Vp>(__r, __f | __allow_partial_loadstore); }
207 template <
typename _Vp = void, __sized_contiguous_range _Rg,
typename... _Flags>
208 [[__gnu__::__always_inline__]]
209 constexpr __vec_load_return_t<_Vp, ranges::range_value_t<_Rg>>
210 partial_load(_Rg&& __r,
const __load_mask_type_t<_Vp, ranges::range_value_t<_Rg>>& __mask,
211 flags<_Flags...> __f = {})
212 {
return simd::unchecked_load<_Vp>(__r, __mask, __f | __allow_partial_loadstore); }
214 template <
typename _Vp = void, contiguous_iterator _It,
typename... _Flags>
215 [[__gnu__::__always_inline__]]
216 constexpr __vec_load_return_t<_Vp, iter_value_t<_It>>
217 partial_load(_It __first, iter_difference_t<_It> __n, flags<_Flags...> __f = {})
218 {
return partial_load<_Vp>(span<
const iter_value_t<_It>>(__first, __n), __f); }
220 template <
typename _Vp = void, contiguous_iterator _It,
typename... _Flags>
221 [[__gnu__::__always_inline__]]
222 constexpr __vec_load_return_t<_Vp, iter_value_t<_It>>
223 partial_load(_It __first, iter_difference_t<_It> __n,
224 const __load_mask_type_t<_Vp, iter_value_t<_It>>& __mask,
225 flags<_Flags...> __f = {})
226 {
return partial_load<_Vp>(span<
const iter_value_t<_It>>(__first, __n), __mask, __f); }
228 template <
typename _Vp =
void, contiguous_iterator _It, sized_sentinel_for<_It> _Sp,
230 [[__gnu__::__always_inline__]]
231 constexpr __vec_load_return_t<_Vp, iter_value_t<_It>>
232 partial_load(_It __first, _Sp __last, flags<_Flags...> __f = {})
233 {
return partial_load<_Vp>(span<
const iter_value_t<_It>>(__first, __last), __f); }
235 template <
typename _Vp =
void, contiguous_iterator _It, sized_sentinel_for<_It> _Sp,
237 [[__gnu__::__always_inline__]]
238 constexpr __vec_load_return_t<_Vp, iter_value_t<_It>>
239 partial_load(_It __first, _Sp __last,
const __load_mask_type_t<_Vp, iter_value_t<_It>>& __mask,
240 flags<_Flags...> __f = {})
241 {
return partial_load<_Vp>(span<
const iter_value_t<_It>>(__first, __last), __mask, __f); }
243 template <
typename _Tp,
typename _Ap, __sized_contiguous_range _Rg,
typename... _Flags>
244 requires indirectly_writable<ranges::iterator_t<_Rg>, _Tp>
245 [[__gnu__::__always_inline__]]
247 unchecked_store(
const basic_vec<_Tp, _Ap>& __v, _Rg&& __r, flags<_Flags...> __f = {})
249 using _TV = basic_vec<_Tp, _Ap>;
250 static_assert(destructible<_TV>);
251 static_assert(__loadstore_convertible_to<_Tp, ranges::range_value_t<_Rg>, _Flags...>,
252 "'flag_convert' must be used for conversions that are not value-preserving");
254 constexpr bool __allow_out_of_bounds = __f._S_test(__allow_partial_loadstore);
255 if constexpr (!__allow_out_of_bounds && ranges::__static_sized_range<_Rg>)
256 static_assert(ranges::size(__r) >= _TV::size(),
"given range must have sufficient size");
258 auto* __ptr = __f.template _S_adjust_pointer<_TV>(ranges::data(__r));
259 const auto __rg_size = ranges::size(__r);
260 if constexpr (!__allow_out_of_bounds)
261 __glibcxx_simd_precondition(
262 ranges::size(__r) >= _TV::size(),
263 "output range is too small. Did you mean to use 'partial_store'?");
267 for (
unsigned __i = 0; __i < __rg_size && __i < _TV::size(); ++__i)
268 __ptr[__i] =
static_cast<ranges::range_value_t<_Rg>
>(__v[__i]);
272 if constexpr (!__allow_out_of_bounds)
275 _TV::_S_partial_store(__v, __ptr, __rg_size);
279 template <
typename _Tp,
typename _Ap, __sized_contiguous_range _Rg,
typename... _Flags>
280 requires indirectly_writable<ranges::iterator_t<_Rg>, _Tp>
281 [[__gnu__::__always_inline__]]
283 unchecked_store(
const basic_vec<_Tp, _Ap>& __v, _Rg&& __r,
284 const typename basic_vec<_Tp, _Ap>::mask_type& __mask,
285 flags<_Flags...> __f = {})
287 using _TV = basic_vec<_Tp, _Ap>;
288 static_assert(__loadstore_convertible_to<_Tp, ranges::range_value_t<_Rg>, _Flags...>,
289 "'flag_convert' must be used for conversions that are not value-preserving");
291 constexpr bool __allow_out_of_bounds = __f._S_test(__allow_partial_loadstore);
292 if constexpr (!__allow_out_of_bounds && ranges::__static_sized_range<_Rg>)
293 static_assert(ranges::size(__r) >= _TV::size(),
"given range must have sufficient size");
295 auto* __ptr = __f.template _S_adjust_pointer<_TV>(ranges::data(__r));
297 if constexpr (!__allow_out_of_bounds)
298 __glibcxx_simd_precondition(
299 ranges::size(__r) >=
size_t(_TV::size()),
300 "output range is too small. Did you mean to use 'partial_store'?");
302 const size_t __rg_size = ranges::size(__r);
305 for (
int __i = 0; __i < _TV::size(); ++__i)
307 if (__mask[__i] && (!__allow_out_of_bounds ||
size_t(__i) < __rg_size))
308 __ptr[__i] =
static_cast<ranges::range_value_t<_Rg>
>(__v[__i]);
313 if (__allow_out_of_bounds && __rg_size <
size_t(_TV::size()))
314 _TV::_S_masked_store(__v, __ptr,
315 __mask && _TV::mask_type::_S_partial_mask_of_n(
int(__rg_size)));
317 _TV::_S_masked_store(__v, __ptr, __mask);
321 template <
typename _Tp,
typename _Ap, contiguous_iterator _It,
typename... _Flags>
322 requires indirectly_writable<_It, _Tp>
323 [[__gnu__::__always_inline__]]
325 unchecked_store(
const basic_vec<_Tp, _Ap>& __v, _It __first,
326 iter_difference_t<_It> __n, flags<_Flags...> __f = {})
327 { simd::unchecked_store(__v, std::span<iter_value_t<_It>>(__first, __n), __f); }
329 template <
typename _Tp,
typename _Ap, contiguous_iterator _It,
typename... _Flags>
330 requires indirectly_writable<_It, _Tp>
331 [[__gnu__::__always_inline__]]
333 unchecked_store(
const basic_vec<_Tp, _Ap>& __v, _It __first, iter_difference_t<_It> __n,
334 const typename basic_vec<_Tp, _Ap>::mask_type& __mask,
335 flags<_Flags...> __f = {})
336 { simd::unchecked_store(__v, std::span<iter_value_t<_It>>(__first, __n), __mask, __f); }
338 template <
typename _Tp,
typename _Ap, contiguous_iterator _It, sized_sentinel_for<_It> _Sp,
340 requires indirectly_writable<_It, _Tp>
341 [[__gnu__::__always_inline__]]
343 unchecked_store(
const basic_vec<_Tp, _Ap>& __v, _It __first, _Sp __last,
344 flags<_Flags...> __f = {})
345 { simd::unchecked_store(__v, std::span<iter_value_t<_It>>(__first, __last), __f); }
347 template <
typename _Tp,
typename _Ap, contiguous_iterator _It, sized_sentinel_for<_It> _Sp,
349 requires indirectly_writable<_It, _Tp>
350 [[__gnu__::__always_inline__]]
352 unchecked_store(
const basic_vec<_Tp, _Ap>& __v, _It __first, _Sp __last,
353 const typename basic_vec<_Tp, _Ap>::mask_type& __mask,
354 flags<_Flags...> __f = {})
355 { simd::unchecked_store(__v, std::span<iter_value_t<_It>>(__first, __last), __mask, __f); }
357 template <
typename _Tp,
typename _Ap, __sized_contiguous_range _Rg,
typename... _Flags>
358 requires indirectly_writable<ranges::iterator_t<_Rg>, _Tp>
359 [[__gnu__::__always_inline__]]
361 partial_store(
const basic_vec<_Tp, _Ap>& __v, _Rg&& __r, flags<_Flags...> __f = {})
362 { simd::unchecked_store(__v, __r, __f | __allow_partial_loadstore); }
364 template <
typename _Tp,
typename _Ap, __sized_contiguous_range _Rg,
typename... _Flags>
365 requires indirectly_writable<ranges::iterator_t<_Rg>, _Tp>
366 [[__gnu__::__always_inline__]]
368 partial_store(
const basic_vec<_Tp, _Ap>& __v, _Rg&& __r,
369 const typename basic_vec<_Tp, _Ap>::mask_type& __mask,
370 flags<_Flags...> __f = {})
371 { simd::unchecked_store(__v, __r, __mask, __f | __allow_partial_loadstore); }
373 template <
typename _Tp,
typename _Ap, contiguous_iterator _It,
typename... _Flags>
374 requires indirectly_writable<_It, _Tp>
375 [[__gnu__::__always_inline__]]
377 partial_store(
const basic_vec<_Tp, _Ap>& __v, _It __first, iter_difference_t<_It> __n,
378 flags<_Flags...> __f = {})
379 { partial_store(__v, span(__first, __n), __f); }
381 template <
typename _Tp,
typename _Ap, contiguous_iterator _It,
typename... _Flags>
382 requires indirectly_writable<_It, _Tp>
383 [[__gnu__::__always_inline__]]
385 partial_store(
const basic_vec<_Tp, _Ap>& __v, _It __first, iter_difference_t<_It> __n,
386 const typename basic_vec<_Tp, _Ap>::mask_type& __mask, flags<_Flags...> __f = {})
387 { partial_store(__v, span(__first, __n), __mask, __f); }
389 template <
typename _Tp,
typename _Ap, contiguous_iterator _It, sized_sentinel_for<_It> _Sp,
391 requires indirectly_writable<_It, _Tp>
392 [[__gnu__::__always_inline__]]
394 partial_store(
const basic_vec<_Tp, _Ap>& __v, _It __first, _Sp __last,
395 flags<_Flags...> __f = {})
396 { partial_store(__v, span(__first, __last), __f); }
398 template <
typename _Tp,
typename _Ap, contiguous_iterator _It, sized_sentinel_for<_It> _Sp,
400 requires indirectly_writable<_It, _Tp>
401 [[__gnu__::__always_inline__]]
403 partial_store(
const basic_vec<_Tp, _Ap>& __v, _It __first, _Sp __last,
404 const typename basic_vec<_Tp, _Ap>::mask_type& __mask, flags<_Flags...> __f = {})
405 { partial_store(__v, span(__first, __last), __mask, __f); }
407_GLIBCXX_END_NAMESPACE_VERSION
410#pragma GCC diagnostic pop
ISO C++ entities toplevel namespace is std.