1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 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 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H 11 #define _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H 12 13 #include <__config> 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> 22 23 _LIBCPP_PUSH_MACROS 24 #include <__undef_macros> 25 26 #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) 27 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> 33 friend class simd; 34 template <class, class> 35 friend class simd_mask; 36 37 _Storage& __s_; 38 size_t __idx_; 39 40 _LIBCPP_HIDE_FROM_ABI __simd_reference(_Storage& __s, size_t __idx) : __s_(__s), __idx_(__idx) {} 41 42 _LIBCPP_HIDE_FROM_ABI _Vp __get() const noexcept { return __s_.__get(__idx_); } 43 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)); 47 else 48 __s_.__set(__idx_, __v); 49 } 50 51 public: 52 using value_type = _Vp; 53 54 __simd_reference() = delete; 55 __simd_reference(const __simd_reference&) = delete; 56 57 _LIBCPP_HIDE_FROM_ABI operator value_type() const noexcept { return __get(); } 58 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_}; 63 } 64 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> 68 friend void 69 swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept; 70 71 template <class _Tp1, class _Storage1, class _Vp1> 72 friend void swap(_Vp1& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept; 73 74 template <class _Tp1, class _Storage1, class _Vp1> 75 friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept; 76 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_}; 81 } 82 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_}; 87 } 88 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_}; 93 } 94 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_}; 99 } 100 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_}; 105 } 106 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_}; 111 } 112 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_}; 117 } 118 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_}; 123 } 124 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_}; 129 } 130 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_}; 135 } 136 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 { 141 __set(__get() + 1); 142 return {__s_, __idx_}; 143 } 144 145 value_type _LIBCPP_HIDE_FROM_ABI operator++(int) && noexcept { 146 auto __r = __get(); 147 __set(__get() + 1); 148 return __r; 149 } 150 151 __simd_reference _LIBCPP_HIDE_FROM_ABI operator--() && noexcept { 152 __set(__get() - 1); 153 return {__s_, __idx_}; 154 } 155 156 value_type _LIBCPP_HIDE_FROM_ABI operator--(int) && noexcept { 157 auto __r = __get(); 158 __set(__get() - 1); 159 return __r; 160 } 161 }; 162 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); 169 } 170 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); 176 } 177 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); 183 } 184 185 } // namespace parallelism_v2 186 _LIBCPP_END_NAMESPACE_EXPERIMENTAL 187 188 #endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) 189 190 _LIBCPP_POP_MACROS 191 192 #endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H 193