xref: /llvm-project/libcxx/include/experimental/__simd/reference.h (revision e99c4906e44ae3f921fa05356909d006cda8d954)
1e7a45c6dSZhangyin // -*- C++ -*-
2e7a45c6dSZhangyin //===----------------------------------------------------------------------===//
3e7a45c6dSZhangyin //
4e7a45c6dSZhangyin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5e7a45c6dSZhangyin // See https://llvm.org/LICENSE.txt for license information.
6e7a45c6dSZhangyin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7e7a45c6dSZhangyin //
8e7a45c6dSZhangyin //===----------------------------------------------------------------------===//
9e7a45c6dSZhangyin 
10e7a45c6dSZhangyin #ifndef _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H
11e7a45c6dSZhangyin #define _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H
12e7a45c6dSZhangyin 
13118f120eSLouis Dionne #include <__config>
14*e99c4906SNikolas Klauser #include <__cstddef/size_t.h>
15d6832a61SLouis Dionne #include <__type_traits/enable_if.h>
16cf0f6a14SZhangYin #include <__type_traits/is_assignable.h>
171314e877Sphilnik777 #include <__type_traits/is_same.h>
18899055f2SZhangYin #include <__utility/declval.h>
191314e877Sphilnik777 #include <__utility/forward.h>
206ec1ddfdSZhangYin #include <__utility/move.h>
21e7a45c6dSZhangyin #include <experimental/__simd/utility.h>
22e7a45c6dSZhangyin 
236ec1ddfdSZhangYin _LIBCPP_PUSH_MACROS
246ec1ddfdSZhangYin #include <__undef_macros>
256ec1ddfdSZhangYin 
26e7a45c6dSZhangyin #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
27e7a45c6dSZhangyin 
28e7a45c6dSZhangyin _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
29e7a45c6dSZhangyin inline namespace parallelism_v2 {
30e7a45c6dSZhangyin template <class _Tp, class _Storage, class _Vp>
31e7a45c6dSZhangyin class __simd_reference {
32e7a45c6dSZhangyin   template <class, class>
33e7a45c6dSZhangyin   friend class simd;
34e7a45c6dSZhangyin   template <class, class>
35e7a45c6dSZhangyin   friend class simd_mask;
36e7a45c6dSZhangyin 
37e7a45c6dSZhangyin   _Storage& __s_;
38e7a45c6dSZhangyin   size_t __idx_;
39e7a45c6dSZhangyin 
40dc534106SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference(_Storage& __s, size_t __idx) : __s_(__s), __idx_(__idx) {}
41dc534106SZhangYin 
42dc534106SZhangYin   _LIBCPP_HIDE_FROM_ABI _Vp __get() const noexcept { return __s_.__get(__idx_); }
43e7a45c6dSZhangyin 
44e7a45c6dSZhangyin   _LIBCPP_HIDE_FROM_ABI void __set(_Vp __v) {
45e7a45c6dSZhangyin     if constexpr (is_same_v<_Vp, bool>)
46e7a45c6dSZhangyin       __s_.__set(__idx_, experimental::__set_all_bits<_Tp>(__v));
47e7a45c6dSZhangyin     else
48e7a45c6dSZhangyin       __s_.__set(__idx_, __v);
49e7a45c6dSZhangyin   }
50e7a45c6dSZhangyin 
51e7a45c6dSZhangyin public:
52e7a45c6dSZhangyin   using value_type = _Vp;
53e7a45c6dSZhangyin 
54e7a45c6dSZhangyin   __simd_reference()                        = delete;
55e7a45c6dSZhangyin   __simd_reference(const __simd_reference&) = delete;
56dc534106SZhangYin 
57dc534106SZhangYin   _LIBCPP_HIDE_FROM_ABI operator value_type() const noexcept { return __get(); }
58cf0f6a14SZhangYin 
59cf0f6a14SZhangYin   template <class _Up, enable_if_t<is_assignable_v<value_type&, _Up&&>, int> = 0>
60cf0f6a14SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator=(_Up&& __v) && noexcept {
61cf0f6a14SZhangYin     __set(static_cast<value_type>(std::forward<_Up>(__v)));
62cf0f6a14SZhangYin     return {__s_, __idx_};
63cf0f6a14SZhangYin   }
646ec1ddfdSZhangYin 
656ec1ddfdSZhangYin   // Note: This approach might not fully align with the specification,
666ec1ddfdSZhangYin   // which might be a wording defect. (https://wg21.link/N4808 section 9.6.3)
676ec1ddfdSZhangYin   template <class _Tp1, class _Storage1, class _Vp1>
686ec1ddfdSZhangYin   friend void
696ec1ddfdSZhangYin   swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept;
706ec1ddfdSZhangYin 
716ec1ddfdSZhangYin   template <class _Tp1, class _Storage1, class _Vp1>
726ec1ddfdSZhangYin   friend void swap(_Vp1& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept;
736ec1ddfdSZhangYin 
746ec1ddfdSZhangYin   template <class _Tp1, class _Storage1, class _Vp1>
756ec1ddfdSZhangYin   friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept;
76899055f2SZhangYin 
77899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() += std::declval<_Up>())>
78899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator+=(_Up&& __v) && noexcept {
79899055f2SZhangYin     __set(__get() + static_cast<value_type>(std::forward<_Up>(__v)));
80899055f2SZhangYin     return {__s_, __idx_};
81899055f2SZhangYin   }
82899055f2SZhangYin 
83899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() -= std::declval<_Up>())>
84899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator-=(_Up&& __v) && noexcept {
85899055f2SZhangYin     __set(__get() - static_cast<value_type>(std::forward<_Up>(__v)));
86899055f2SZhangYin     return {__s_, __idx_};
87899055f2SZhangYin   }
88899055f2SZhangYin 
89899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() *= std::declval<_Up>())>
90899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator*=(_Up&& __v) && noexcept {
91899055f2SZhangYin     __set(__get() * static_cast<value_type>(std::forward<_Up>(__v)));
92899055f2SZhangYin     return {__s_, __idx_};
93899055f2SZhangYin   }
94899055f2SZhangYin 
95899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() /= std::declval<_Up>())>
96899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator/=(_Up&& __v) && noexcept {
97899055f2SZhangYin     __set(__get() / static_cast<value_type>(std::forward<_Up>(__v)));
98899055f2SZhangYin     return {__s_, __idx_};
99899055f2SZhangYin   }
100899055f2SZhangYin 
101899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() %= std::declval<_Up>())>
102899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator%=(_Up&& __v) && noexcept {
103899055f2SZhangYin     __set(__get() % static_cast<value_type>(std::forward<_Up>(__v)));
104899055f2SZhangYin     return {__s_, __idx_};
105899055f2SZhangYin   }
106899055f2SZhangYin 
107899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() &= std::declval<_Up>())>
108899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator&=(_Up&& __v) && noexcept {
109899055f2SZhangYin     __set(__get() & static_cast<value_type>(std::forward<_Up>(__v)));
110899055f2SZhangYin     return {__s_, __idx_};
111899055f2SZhangYin   }
112899055f2SZhangYin 
113899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() |= std::declval<_Up>())>
114899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator|=(_Up&& __v) && noexcept {
115899055f2SZhangYin     __set(__get() | static_cast<value_type>(std::forward<_Up>(__v)));
116899055f2SZhangYin     return {__s_, __idx_};
117899055f2SZhangYin   }
118899055f2SZhangYin 
119899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() ^= std::declval<_Up>())>
120899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator^=(_Up&& __v) && noexcept {
121899055f2SZhangYin     __set(__get() ^ static_cast<value_type>(std::forward<_Up>(__v)));
122899055f2SZhangYin     return {__s_, __idx_};
123899055f2SZhangYin   }
124899055f2SZhangYin 
125899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() <<= std::declval<_Up>())>
126899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator<<=(_Up&& __v) && noexcept {
127899055f2SZhangYin     __set(__get() << static_cast<value_type>(std::forward<_Up>(__v)));
128899055f2SZhangYin     return {__s_, __idx_};
129899055f2SZhangYin   }
130899055f2SZhangYin 
131899055f2SZhangYin   template <class _Up, class = decltype(std::declval<value_type&>() >>= std::declval<_Up>())>
132899055f2SZhangYin   _LIBCPP_HIDE_FROM_ABI __simd_reference operator>>=(_Up&& __v) && noexcept {
133899055f2SZhangYin     __set(__get() >> static_cast<value_type>(std::forward<_Up>(__v)));
134899055f2SZhangYin     return {__s_, __idx_};
135899055f2SZhangYin   }
136812ae91dSZhangYin 
137812ae91dSZhangYin   // Note: All legal vectorizable types support operator++/--.
138812ae91dSZhangYin   // There doesn't seem to be a way to trigger the constraint.
139812ae91dSZhangYin   // Therefore, no SFINAE check is added here.
140812ae91dSZhangYin   __simd_reference _LIBCPP_HIDE_FROM_ABI operator++() && noexcept {
141812ae91dSZhangYin     __set(__get() + 1);
142812ae91dSZhangYin     return {__s_, __idx_};
143812ae91dSZhangYin   }
144812ae91dSZhangYin 
145812ae91dSZhangYin   value_type _LIBCPP_HIDE_FROM_ABI operator++(int) && noexcept {
146812ae91dSZhangYin     auto __r = __get();
147812ae91dSZhangYin     __set(__get() + 1);
148812ae91dSZhangYin     return __r;
149812ae91dSZhangYin   }
150812ae91dSZhangYin 
151812ae91dSZhangYin   __simd_reference _LIBCPP_HIDE_FROM_ABI operator--() && noexcept {
152812ae91dSZhangYin     __set(__get() - 1);
153812ae91dSZhangYin     return {__s_, __idx_};
154812ae91dSZhangYin   }
155812ae91dSZhangYin 
156812ae91dSZhangYin   value_type _LIBCPP_HIDE_FROM_ABI operator--(int) && noexcept {
157812ae91dSZhangYin     auto __r = __get();
158812ae91dSZhangYin     __set(__get() - 1);
159812ae91dSZhangYin     return __r;
160812ae91dSZhangYin   }
161e7a45c6dSZhangyin };
162e7a45c6dSZhangyin 
1636ec1ddfdSZhangYin template <class _Tp, class _Storage, class _Vp>
1646ec1ddfdSZhangYin _LIBCPP_HIDE_FROM_ABI void
1656ec1ddfdSZhangYin swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept {
1666ec1ddfdSZhangYin   _Vp __tmp(std::move(__a));
1676ec1ddfdSZhangYin   std::move(__a) = std::move(__b);
1686ec1ddfdSZhangYin   std::move(__b) = std::move(__tmp);
1696ec1ddfdSZhangYin }
1706ec1ddfdSZhangYin 
1716ec1ddfdSZhangYin template <class _Tp, class _Storage, class _Vp>
1726ec1ddfdSZhangYin _LIBCPP_HIDE_FROM_ABI void swap(_Vp& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept {
1736ec1ddfdSZhangYin   _Vp __tmp(std::move(__a));
1746ec1ddfdSZhangYin   __a            = std::move(__b);
1756ec1ddfdSZhangYin   std::move(__b) = std::move(__tmp);
1766ec1ddfdSZhangYin }
1776ec1ddfdSZhangYin 
1786ec1ddfdSZhangYin template <class _Tp, class _Storage, class _Vp>
1796ec1ddfdSZhangYin _LIBCPP_HIDE_FROM_ABI void swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, _Vp& __b) noexcept {
1806ec1ddfdSZhangYin   _Vp __tmp(std::move(__a));
1816ec1ddfdSZhangYin   std::move(__a) = std::move(__b);
1826ec1ddfdSZhangYin   __b            = std::move(__tmp);
1836ec1ddfdSZhangYin }
1846ec1ddfdSZhangYin 
185e7a45c6dSZhangyin } // namespace parallelism_v2
186e7a45c6dSZhangyin _LIBCPP_END_NAMESPACE_EXPERIMENTAL
187e7a45c6dSZhangyin 
188e7a45c6dSZhangyin #endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
1896ec1ddfdSZhangYin 
1906ec1ddfdSZhangYin _LIBCPP_POP_MACROS
1916ec1ddfdSZhangYin 
192e7a45c6dSZhangyin #endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H
193