2 //===----------------------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP_EXPERIMENTAL___SIMD_SIMD_H
11 #define _LIBCPP_EXPERIMENTAL___SIMD_SIMD_H
14 #include <__cstddef/size_t.h>
15 #include <__type_traits/enable_if.h>
16 #include <__type_traits/is_integral.h>
17 #include <__type_traits/is_same.h>
18 #include <__type_traits/remove_cvref.h>
19 #include <__utility/forward.h>
20 #include <experimental/__simd/declaration.h>
21 #include <experimental/__simd/reference.h>
22 #include <experimental/__simd/traits.h>
23 #include <experimental/__simd/utility.h>
25 #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
27 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
28 inline namespace parallelism_v2
{
30 template <class _Simd
, class _Impl
, bool>
31 class __simd_int_operators
{};
33 template <class _Simd
, class _Impl
>
34 class __simd_int_operators
<_Simd
, _Impl
, true> {
36 // unary operators for integral _Tp
37 _LIBCPP_HIDE_FROM_ABI _Simd
operator~() const noexcept
{
38 return _Simd(_Impl::__bitwise_not((*static_cast<const _Simd
*>(this)).__s_
), _Simd::__storage_tag
);
42 // class template simd [simd.class]
43 // TODO: implement simd class
44 template <class _Tp
, class _Abi
>
45 class simd
: public __simd_int_operators
<simd
<_Tp
, _Abi
>, __simd_operations
<_Tp
, _Abi
>, is_integral_v
<_Tp
>> {
46 using _Impl _LIBCPP_NODEBUG
= __simd_operations
<_Tp
, _Abi
>;
47 using _Storage _LIBCPP_NODEBUG
= typename
_Impl::_SimdStorage
;
51 friend class __simd_int_operators
<simd
, _Impl
, true>;
54 using value_type
= _Tp
;
55 using reference
= __simd_reference
<_Tp
, _Storage
, value_type
>;
56 using mask_type
= simd_mask
<_Tp
, _Abi
>;
57 using abi_type
= _Abi
;
59 static _LIBCPP_HIDE_FROM_ABI
constexpr size_t size() noexcept
{ return simd_size_v
<value_type
, abi_type
>; }
61 _LIBCPP_HIDE_FROM_ABI
simd() noexcept
= default;
63 // explicit conversion from and to implementation-defined types
64 struct __storage_tag_t
{};
65 static constexpr __storage_tag_t __storage_tag
{};
66 explicit _LIBCPP_HIDE_FROM_ABI
operator _Storage() const { return __s_
; }
67 explicit _LIBCPP_HIDE_FROM_ABI
simd(const _Storage
& __s
, __storage_tag_t
) : __s_(__s
) {}
69 // broadcast constructor
70 template <class _Up
, enable_if_t
<__can_broadcast_v
<value_type
, __remove_cvref_t
<_Up
>>, int> = 0>
71 _LIBCPP_HIDE_FROM_ABI
simd(_Up
&& __v
) noexcept
: __s_(_Impl::__broadcast(static_cast<value_type
>(__v
))) {}
73 // implicit type conversion constructor
75 enable_if_t
<!is_same_v
<_Up
, _Tp
> && is_same_v
<abi_type
, simd_abi::fixed_size
<size()>> &&
76 __is_non_narrowing_convertible_v
<_Up
, value_type
>,
78 _LIBCPP_HIDE_FROM_ABI
simd(const simd
<_Up
, simd_abi::fixed_size
<size()>>& __v
) noexcept
{
79 for (size_t __i
= 0; __i
< size(); __i
++) {
80 (*this)[__i
] = static_cast<value_type
>(__v
[__i
]);
84 // generator constructor
85 template <class _Generator
, enable_if_t
<__can_generate_v
<value_type
, _Generator
, size()>, int> = 0>
86 explicit _LIBCPP_HIDE_FROM_ABI
simd(_Generator
&& __g
) noexcept
87 : __s_(_Impl::__generate(std::forward
<_Generator
>(__g
))) {}
90 template <class _Up
, class _Flags
, enable_if_t
<__is_vectorizable_v
<_Up
> && is_simd_flag_type_v
<_Flags
>, int> = 0>
91 _LIBCPP_HIDE_FROM_ABI
simd(const _Up
* __mem
, _Flags
) {
92 _Impl::__load(__s_
, _Flags::template __apply
<simd
>(__mem
));
96 template <class _Up
, class _Flags
, enable_if_t
<__is_vectorizable_v
<_Up
> && is_simd_flag_type_v
<_Flags
>, int> = 0>
97 _LIBCPP_HIDE_FROM_ABI
void copy_from(const _Up
* __mem
, _Flags
) {
98 _Impl::__load(__s_
, _Flags::template __apply
<simd
>(__mem
));
101 template <class _Up
, class _Flags
, enable_if_t
<__is_vectorizable_v
<_Up
> && is_simd_flag_type_v
<_Flags
>, int> = 0>
102 _LIBCPP_HIDE_FROM_ABI
void copy_to(_Up
* __mem
, _Flags
) const {
103 _Impl::__store(__s_
, _Flags::template __apply
<simd
>(__mem
));
106 // scalar access [simd.subscr]
107 _LIBCPP_HIDE_FROM_ABI reference
operator[](size_t __i
) noexcept
{ return reference(__s_
, __i
); }
108 _LIBCPP_HIDE_FROM_ABI value_type
operator[](size_t __i
) const noexcept
{ return __s_
.__get(__i
); }
110 // simd unary operators
111 _LIBCPP_HIDE_FROM_ABI simd
& operator++() noexcept
{
112 _Impl::__increment(__s_
);
116 _LIBCPP_HIDE_FROM_ABI simd
operator++(int) noexcept
{
118 _Impl::__increment(__s_
);
122 _LIBCPP_HIDE_FROM_ABI simd
& operator--() noexcept
{
123 _Impl::__decrement(__s_
);
127 _LIBCPP_HIDE_FROM_ABI simd
operator--(int) noexcept
{
129 _Impl::__decrement(__s_
);
133 _LIBCPP_HIDE_FROM_ABI mask_type
operator!() const noexcept
{
134 return mask_type(_Impl::__negate(__s_
), mask_type::__storage_tag
);
137 _LIBCPP_HIDE_FROM_ABI simd
operator+() const noexcept
{ return *this; }
139 _LIBCPP_HIDE_FROM_ABI simd
operator-() const noexcept
{ return simd(_Impl::__unary_minus(__s_
), __storage_tag
); }
142 template <class _Tp
, class _Abi
>
143 inline constexpr bool is_simd_v
<simd
<_Tp
, _Abi
>> = true;
146 using native_simd
= simd
<_Tp
, simd_abi::native
<_Tp
>>;
148 template <class _Tp
, int _Np
>
149 using fixed_size_simd
= simd
<_Tp
, simd_abi::fixed_size
<_Np
>>;
151 } // namespace parallelism_v2
152 _LIBCPP_END_NAMESPACE_EXPERIMENTAL
154 #endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
155 #endif // _LIBCPP_EXPERIMENTAL___SIMD_SIMD_H