master
  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
 29inline 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    else
 48      __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 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
163template <class _Tp, class _Storage, class _Vp>
164_LIBCPP_HIDE_FROM_ABI void
165swap(__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_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