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