193 lines · c
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H11#define _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H12 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_MACROS24#include <__undef_macros>25 26#if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)27 28_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL29inline namespace parallelism_v2 {30template <class _Tp, class _Storage, class _Vp>31class __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 else48 __s_.__set(__idx_, __v);49 }50 51public: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 void69 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 163template <class _Tp, class _Storage, class _Vp>164_LIBCPP_HIDE_FROM_ABI void165swap(__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 171template <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 178template <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_v2186_LIBCPP_END_NAMESPACE_EXPERIMENTAL187 188#endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)189 190_LIBCPP_POP_MACROS191 192#endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H193