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_REFERENCE_H
11 #define _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H
14 #include <__cstddef/size_t.h>
15 #include <__type_traits/enable_if.h>
16 #include <__type_traits/is_assignable.h>
17 #include <__type_traits/is_same.h>
18 #include <__utility/declval.h>
19 #include <__utility/forward.h>
20 #include <__utility/move.h>
21 #include <experimental/__simd/utility.h>
24 #include <__undef_macros>
26 #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
28 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
29 inline namespace parallelism_v2
{
30 template <class _Tp
, class _Storage
, class _Vp
>
31 class __simd_reference
{
32 template <class, class>
34 template <class, class>
35 friend class simd_mask
;
40 _LIBCPP_HIDE_FROM_ABI
__simd_reference(_Storage
& __s
, size_t __idx
) : __s_(__s
), __idx_(__idx
) {}
42 _LIBCPP_HIDE_FROM_ABI _Vp
__get() const noexcept
{ return __s_
.__get(__idx_
); }
44 _LIBCPP_HIDE_FROM_ABI
void __set(_Vp __v
) {
45 if constexpr (is_same_v
<_Vp
, bool>)
46 __s_
.__set(__idx_
, experimental::__set_all_bits
<_Tp
>(__v
));
48 __s_
.__set(__idx_
, __v
);
52 using value_type
= _Vp
;
54 __simd_reference() = delete;
55 __simd_reference(const __simd_reference
&) = delete;
57 _LIBCPP_HIDE_FROM_ABI
operator value_type() const noexcept
{ return __get(); }
59 template <class _Up
, enable_if_t
<is_assignable_v
<value_type
&, _Up
&&>, int> = 0>
60 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator=(_Up
&& __v
) && noexcept
{
61 __set(static_cast<value_type
>(std::forward
<_Up
>(__v
)));
62 return {__s_
, __idx_
};
65 // Note: This approach might not fully align with the specification,
66 // which might be a wording defect. (https://wg21.link/N4808 section 9.6.3)
67 template <class _Tp1
, class _Storage1
, class _Vp1
>
69 swap(__simd_reference
<_Tp1
, _Storage1
, _Vp1
>&& __a
, __simd_reference
<_Tp1
, _Storage1
, _Vp1
>&& __b
) noexcept
;
71 template <class _Tp1
, class _Storage1
, class _Vp1
>
72 friend void swap(_Vp1
& __a
, __simd_reference
<_Tp1
, _Storage1
, _Vp1
>&& __b
) noexcept
;
74 template <class _Tp1
, class _Storage1
, class _Vp1
>
75 friend void swap(__simd_reference
<_Tp1
, _Storage1
, _Vp1
>&& __a
, _Vp1
& __b
) noexcept
;
77 template <class _Up
, class = decltype(std::declval
<value_type
&>() += std::declval
<_Up
>())>
78 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator+=(_Up
&& __v
) && noexcept
{
79 __set(__get() + static_cast<value_type
>(std::forward
<_Up
>(__v
)));
80 return {__s_
, __idx_
};
83 template <class _Up
, class = decltype(std::declval
<value_type
&>() -= std::declval
<_Up
>())>
84 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator-=(_Up
&& __v
) && noexcept
{
85 __set(__get() - static_cast<value_type
>(std::forward
<_Up
>(__v
)));
86 return {__s_
, __idx_
};
89 template <class _Up
, class = decltype(std::declval
<value_type
&>() *= std::declval
<_Up
>())>
90 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator*=(_Up
&& __v
) && noexcept
{
91 __set(__get() * static_cast<value_type
>(std::forward
<_Up
>(__v
)));
92 return {__s_
, __idx_
};
95 template <class _Up
, class = decltype(std::declval
<value_type
&>() /= std::declval
<_Up
>())>
96 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator/=(_Up
&& __v
) && noexcept
{
97 __set(__get() / static_cast<value_type
>(std::forward
<_Up
>(__v
)));
98 return {__s_
, __idx_
};
101 template <class _Up
, class = decltype(std::declval
<value_type
&>() %= std::declval
<_Up
>())>
102 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator%=(_Up
&& __v
) && noexcept
{
103 __set(__get() % static_cast<value_type
>(std::forward
<_Up
>(__v
)));
104 return {__s_
, __idx_
};
107 template <class _Up
, class = decltype(std::declval
<value_type
&>() &= std::declval
<_Up
>())>
108 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator&=(_Up
&& __v
) && noexcept
{
109 __set(__get() & static_cast<value_type
>(std::forward
<_Up
>(__v
)));
110 return {__s_
, __idx_
};
113 template <class _Up
, class = decltype(std::declval
<value_type
&>() |= std::declval
<_Up
>())>
114 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator|=(_Up
&& __v
) && noexcept
{
115 __set(__get() | static_cast<value_type
>(std::forward
<_Up
>(__v
)));
116 return {__s_
, __idx_
};
119 template <class _Up
, class = decltype(std::declval
<value_type
&>() ^= std::declval
<_Up
>())>
120 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator^=(_Up
&& __v
) && noexcept
{
121 __set(__get() ^ static_cast<value_type
>(std::forward
<_Up
>(__v
)));
122 return {__s_
, __idx_
};
125 template <class _Up
, class = decltype(std::declval
<value_type
&>() <<= std::declval
<_Up
>())>
126 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator<<=(_Up
&& __v
) && noexcept
{
127 __set(__get() << static_cast<value_type
>(std::forward
<_Up
>(__v
)));
128 return {__s_
, __idx_
};
131 template <class _Up
, class = decltype(std::declval
<value_type
&>() >>= std::declval
<_Up
>())>
132 _LIBCPP_HIDE_FROM_ABI __simd_reference
operator>>=(_Up
&& __v
) && noexcept
{
133 __set(__get() >> static_cast<value_type
>(std::forward
<_Up
>(__v
)));
134 return {__s_
, __idx_
};
137 // Note: All legal vectorizable types support operator++/--.
138 // There doesn't seem to be a way to trigger the constraint.
139 // Therefore, no SFINAE check is added here.
140 __simd_reference _LIBCPP_HIDE_FROM_ABI
operator++() && noexcept
{
142 return {__s_
, __idx_
};
145 value_type _LIBCPP_HIDE_FROM_ABI
operator++(int) && noexcept
{
151 __simd_reference _LIBCPP_HIDE_FROM_ABI
operator--() && noexcept
{
153 return {__s_
, __idx_
};
156 value_type _LIBCPP_HIDE_FROM_ABI
operator--(int) && noexcept
{
163 template <class _Tp
, class _Storage
, class _Vp
>
164 _LIBCPP_HIDE_FROM_ABI
void
165 swap(__simd_reference
<_Tp
, _Storage
, _Vp
>&& __a
, __simd_reference
<_Tp
, _Storage
, _Vp
>&& __b
) noexcept
{
166 _Vp
__tmp(std::move(__a
));
167 std::move(__a
) = std::move(__b
);
168 std::move(__b
) = std::move(__tmp
);
171 template <class _Tp
, class _Storage
, class _Vp
>
172 _LIBCPP_HIDE_FROM_ABI
void swap(_Vp
& __a
, __simd_reference
<_Tp
, _Storage
, _Vp
>&& __b
) noexcept
{
173 _Vp
__tmp(std::move(__a
));
174 __a
= std::move(__b
);
175 std::move(__b
) = std::move(__tmp
);
178 template <class _Tp
, class _Storage
, class _Vp
>
179 _LIBCPP_HIDE_FROM_ABI
void swap(__simd_reference
<_Tp
, _Storage
, _Vp
>&& __a
, _Vp
& __b
) noexcept
{
180 _Vp
__tmp(std::move(__a
));
181 std::move(__a
) = std::move(__b
);
182 __b
= std::move(__tmp
);
185 } // namespace parallelism_v2
186 _LIBCPP_END_NAMESPACE_EXPERIMENTAL
188 #endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
192 #endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H