diff options
5 files changed, 278 insertions, 5 deletions
diff --git a/libcxx/docs/Status/ParallelismProjects.csv b/libcxx/docs/Status/ParallelismProjects.csv index 06087e3..d518609 100644 --- a/libcxx/docs/Status/ParallelismProjects.csv +++ b/libcxx/docs/Status/ParallelismProjects.csv @@ -17,6 +17,7 @@ Section,Description,Dependencies,Assignee,Complete | `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references operator value_type() <https://github.com/llvm/llvm-project/pull/68960>`_", None, Yin Zhang, |Complete| | `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references operator= <https://github.com/llvm/llvm-project/pull/70020>`_", None, Yin Zhang, |Complete| | `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references swap functions <https://github.com/llvm/llvm-project/pull/86478>`_", None, Yin Zhang, |Complete| +| `[parallel.simd.reference] <https://wg21.link/N4808>`_, "`Element references compound assignment operators <https://github.com/llvm/llvm-project/pull/86761>`_", None, Yin Zhang, |Complete| | `[parallel.simd.class] <https://wg21.link/N4808>`_, "`Class template simd declaration and alias <https://reviews.llvm.org/D144362>`_", [parallel.simd.abi], Yin Zhang, |Complete| | `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd<>::size() <https://reviews.llvm.org/D144363>`_", [parallel.simd.traits] simd_size[_v], Yin Zhang, |Complete| | `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd default constructor <https://github.com/llvm/llvm-project/pull/70424>`_", None, Yin Zhang, |Complete| diff --git a/libcxx/include/experimental/__simd/reference.h b/libcxx/include/experimental/__simd/reference.h index af61dbc..f5bb3ba 100644 --- a/libcxx/include/experimental/__simd/reference.h +++ b/libcxx/include/experimental/__simd/reference.h @@ -12,6 +12,7 @@ #include <__type_traits/is_assignable.h> #include <__type_traits/is_same.h> +#include <__utility/declval.h> #include <__utility/forward.h> #include <__utility/move.h> #include <cstddef> @@ -71,6 +72,66 @@ public: template <class _Tp1, class _Storage1, class _Vp1> friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept; + + template <class _Up, class = decltype(std::declval<value_type&>() += std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator+=(_Up&& __v) && noexcept { + __set(__get() + static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() -= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator-=(_Up&& __v) && noexcept { + __set(__get() - static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() *= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator*=(_Up&& __v) && noexcept { + __set(__get() * static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() /= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator/=(_Up&& __v) && noexcept { + __set(__get() / static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() %= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator%=(_Up&& __v) && noexcept { + __set(__get() % static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() &= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator&=(_Up&& __v) && noexcept { + __set(__get() & static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() |= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator|=(_Up&& __v) && noexcept { + __set(__get() | static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() ^= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator^=(_Up&& __v) && noexcept { + __set(__get() ^ static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() <<= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator<<=(_Up&& __v) && noexcept { + __set(__get() << static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template <class _Up, class = decltype(std::declval<value_type&>() >>= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator>>=(_Up&& __v) && noexcept { + __set(__get() >> static_cast<value_type>(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } }; template <class _Tp, class _Storage, class _Vp> diff --git a/libcxx/test/std/experimental/simd/simd.reference/reference_arith_operators.pass.cpp b/libcxx/test/std/experimental/simd/simd.reference/reference_arith_operators.pass.cpp new file mode 100644 index 0000000..2a4a134 --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.reference/reference_arith_operators.pass.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// <experimental/simd> +// +// [simd.reference] +// template<class U> reference+=(U&& x) && noexcept; +// template<class U> reference-=(U&& x) && noexcept; +// template<class U> reference*=(U&& x) && noexcept; +// template<class U> reference/=(U&& x) && noexcept; +// template<class U> reference%=(U&& x) && noexcept; + +#include "../test_utils.h" +#include <experimental/simd> + +namespace ex = std::experimental::parallelism_v2; + +struct PlusAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) += rhs; + } +}; + +struct MinusAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) -= rhs; + } +}; + +struct MultipliesAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) *= rhs; + } +}; + +struct DividesAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) /= rhs; + } +}; + +struct ModulusAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) %= rhs; + } +}; + +template <typename T, typename SimdAbi, typename Op, typename OpAssign> +struct SimdReferenceOperatorHelper { + template <class U> + void operator()() const { + ex::simd<T, SimdAbi> origin_simd(static_cast<T>(3)); + static_assert(noexcept(OpAssign{}(origin_simd[0], static_cast<U>(2)))); + OpAssign{}(origin_simd[0], static_cast<U>(2)); + assert((T)origin_simd[0] == (T)Op{}(static_cast<T>(3), static_cast<T>(std::forward<U>(2)))); + } +}; + +template <class T, std::size_t> +struct CheckReferenceArithOperators { + template <class SimdAbi> + void operator()() { + types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::plus<>, PlusAssign>()); + types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::minus<>, MinusAssign>()); + types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::multiplies<>, MultipliesAssign>()); + types::for_each(simd_test_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::divides<>, DividesAssign>()); + } +}; + +template <class T, std::size_t> +struct CheckReferenceModOperators { + template <class SimdAbi> + void operator()() { + types::for_each( + simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::modulus<>, ModulusAssign>()); + } +}; + +int main(int, char**) { + test_all_simd_abi<CheckReferenceArithOperators>(); + types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckReferenceModOperators>()); + return 0; +} diff --git a/libcxx/test/std/experimental/simd/simd.reference/reference_bitwise_operators.pass.cpp b/libcxx/test/std/experimental/simd/simd.reference/reference_bitwise_operators.pass.cpp new file mode 100644 index 0000000..340b92c --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.reference/reference_bitwise_operators.pass.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// <experimental/simd> +// +// [simd.reference] +// template<class U> reference|=(U&& x) && noexcept; +// template<class U> reference&=(U&& x) && noexcept; +// template<class U> reference^=(U&& x) && noexcept; +// template<class U> reference<<=(U&& x) && noexcept; +// template<class U> reference>>=(U&& x) && noexcept; + +#include "../test_utils.h" +#include <experimental/simd> + +namespace ex = std::experimental::parallelism_v2; + +struct AndAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) &= rhs; + } +}; + +struct OrAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) |= rhs; + } +}; + +struct XorAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) ^= rhs; + } +}; + +struct LeftShiftAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) <<= rhs; + } +}; + +struct RightShiftAssign { + template <typename T, typename U> + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward<T>(lhs) >>= rhs; + } +}; + +struct LeftShift { + template <typename T, typename U> + T operator()(const T& lhs, const U& rhs) const noexcept { + return lhs << rhs; + } +}; + +struct RightShift { + template <typename T, typename U> + T operator()(const T& lhs, const U& rhs) const noexcept { + return lhs >> rhs; + } +}; + +template <typename T, typename SimdAbi, typename Op, typename OpAssign> +struct SimdReferenceOperatorHelper { + template <class U> + void operator()() const { + ex::simd<T, SimdAbi> origin_simd(static_cast<T>(3)); + static_assert(noexcept(OpAssign{}(origin_simd[0], static_cast<U>(2)))); + OpAssign{}(origin_simd[0], static_cast<U>(2)); + assert((T)origin_simd[0] == (T)Op{}(static_cast<T>(3), static_cast<T>(std::forward<U>(2)))); + } +}; + +template <typename T, typename SimdAbi, typename Op, typename OpAssign> +struct MaskReferenceOperatorHelper { + template <class U> + void operator()() const { + ex::simd_mask<T, SimdAbi> origin_mask(true); + static_assert(noexcept(OpAssign{}(origin_mask[0], static_cast<U>(false)))); + OpAssign{}(origin_mask[0], static_cast<U>(false)); + assert((bool)origin_mask[0] == (bool)Op{}(true, static_cast<bool>(std::forward<U>(false)))); + } +}; + +template <class T, std::size_t> +struct CheckReferenceBitwiseOperators { + template <class SimdAbi> + void operator()() { + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_and<>, AndAssign>()); + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_or<>, OrAssign>()); + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, std::bit_xor<>, XorAssign>()); + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, LeftShift, LeftShiftAssign>()); + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper<T, SimdAbi, RightShift, RightShiftAssign>()); + + types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_and<>, AndAssign>()); + types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_or<>, OrAssign>()); + types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper<T, SimdAbi, std::bit_xor<>, XorAssign>()); + } +}; + +int main(int, char**) { + types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckReferenceBitwiseOperators>()); + return 0; +} diff --git a/libcxx/test/std/experimental/simd/test_utils.h b/libcxx/test/std/experimental/simd/test_utils.h index 9b44160..3c227a4 100644 --- a/libcxx/test/std/experimental/simd/test_utils.h +++ b/libcxx/test/std/experimental/simd/test_utils.h @@ -50,15 +50,16 @@ using arithmetic_no_bool_types = types::concatenate_t<types::integer_types, type // For interfaces with vectorizable type template parameters, we only use some common or boundary types // as template parameters for testing to ensure that the compilation time of a single test does not exceed. -using simd_test_types = +using simd_test_integer_types = types::type_list<char, unsigned, - int, + int #ifndef TEST_HAS_NO_INT128 - __int128_t, + , + __int128_t #endif - float, - double>; + >; +using simd_test_types = types::concatenate_t<simd_test_integer_types, types::type_list<float, double>>; template <template <class T, std::size_t N> class Func> void test_all_simd_abi() { |