From 899055f20bf5a17e63544892794982e4a6ef2822 Mon Sep 17 00:00:00 2001 From: ZhangYin Date: Sun, 4 Aug 2024 10:16:56 +0800 Subject: [libc++] Add compound assignment operators for simd reference (#86761) --- libcxx/docs/Status/ParallelismProjects.csv | 1 + libcxx/include/experimental/__simd/reference.h | 61 +++++++++++ .../reference_arith_operators.pass.cpp | 95 +++++++++++++++++ .../reference_bitwise_operators.pass.cpp | 115 +++++++++++++++++++++ libcxx/test/std/experimental/simd/test_utils.h | 11 +- 5 files changed, 278 insertions(+), 5 deletions(-) create mode 100644 libcxx/test/std/experimental/simd/simd.reference/reference_arith_operators.pass.cpp create mode 100644 libcxx/test/std/experimental/simd/simd.reference/reference_bitwise_operators.pass.cpp 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] `_, "`Element references operator value_type() `_", None, Yin Zhang, |Complete| | `[parallel.simd.reference] `_, "`Element references operator= `_", None, Yin Zhang, |Complete| | `[parallel.simd.reference] `_, "`Element references swap functions `_", None, Yin Zhang, |Complete| +| `[parallel.simd.reference] `_, "`Element references compound assignment operators `_", None, Yin Zhang, |Complete| | `[parallel.simd.class] `_, "`Class template simd declaration and alias `_", [parallel.simd.abi], Yin Zhang, |Complete| | `[parallel.simd.class] `_, "`simd<>::size() `_", [parallel.simd.traits] simd_size[_v], Yin Zhang, |Complete| | `[parallel.simd.class] `_, "`simd default constructor `_", 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 @@ -71,6 +72,66 @@ public: template friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept; + + template () += std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator+=(_Up&& __v) && noexcept { + __set(__get() + static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () -= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator-=(_Up&& __v) && noexcept { + __set(__get() - static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () *= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator*=(_Up&& __v) && noexcept { + __set(__get() * static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () /= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator/=(_Up&& __v) && noexcept { + __set(__get() / static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () %= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator%=(_Up&& __v) && noexcept { + __set(__get() % static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () &= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator&=(_Up&& __v) && noexcept { + __set(__get() & static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () |= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator|=(_Up&& __v) && noexcept { + __set(__get() | static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () ^= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator^=(_Up&& __v) && noexcept { + __set(__get() ^ static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () <<= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator<<=(_Up&& __v) && noexcept { + __set(__get() << static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } + + template () >>= std::declval<_Up>())> + _LIBCPP_HIDE_FROM_ABI __simd_reference operator>>=(_Up&& __v) && noexcept { + __set(__get() >> static_cast(std::forward<_Up>(__v))); + return {__s_, __idx_}; + } }; template 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 + +// +// +// [simd.reference] +// template reference+=(U&& x) && noexcept; +// template reference-=(U&& x) && noexcept; +// template reference*=(U&& x) && noexcept; +// template reference/=(U&& x) && noexcept; +// template reference%=(U&& x) && noexcept; + +#include "../test_utils.h" +#include + +namespace ex = std::experimental::parallelism_v2; + +struct PlusAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) += rhs; + } +}; + +struct MinusAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) -= rhs; + } +}; + +struct MultipliesAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) *= rhs; + } +}; + +struct DividesAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) /= rhs; + } +}; + +struct ModulusAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) %= rhs; + } +}; + +template +struct SimdReferenceOperatorHelper { + template + void operator()() const { + ex::simd origin_simd(static_cast(3)); + static_assert(noexcept(OpAssign{}(origin_simd[0], static_cast(2)))); + OpAssign{}(origin_simd[0], static_cast(2)); + assert((T)origin_simd[0] == (T)Op{}(static_cast(3), static_cast(std::forward(2)))); + } +}; + +template +struct CheckReferenceArithOperators { + template + void operator()() { + types::for_each(simd_test_types(), SimdReferenceOperatorHelper, PlusAssign>()); + types::for_each(simd_test_types(), SimdReferenceOperatorHelper, MinusAssign>()); + types::for_each(simd_test_types(), SimdReferenceOperatorHelper, MultipliesAssign>()); + types::for_each(simd_test_types(), SimdReferenceOperatorHelper, DividesAssign>()); + } +}; + +template +struct CheckReferenceModOperators { + template + void operator()() { + types::for_each( + simd_test_integer_types(), SimdReferenceOperatorHelper, ModulusAssign>()); + } +}; + +int main(int, char**) { + test_all_simd_abi(); + types::for_each(types::integer_types(), TestAllSimdAbiFunctor()); + 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 + +// +// +// [simd.reference] +// template reference|=(U&& x) && noexcept; +// template reference&=(U&& x) && noexcept; +// template reference^=(U&& x) && noexcept; +// template reference<<=(U&& x) && noexcept; +// template reference>>=(U&& x) && noexcept; + +#include "../test_utils.h" +#include + +namespace ex = std::experimental::parallelism_v2; + +struct AndAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) &= rhs; + } +}; + +struct OrAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) |= rhs; + } +}; + +struct XorAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) ^= rhs; + } +}; + +struct LeftShiftAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) <<= rhs; + } +}; + +struct RightShiftAssign { + template + void operator()(T&& lhs, const U& rhs) const noexcept { + std::forward(lhs) >>= rhs; + } +}; + +struct LeftShift { + template + T operator()(const T& lhs, const U& rhs) const noexcept { + return lhs << rhs; + } +}; + +struct RightShift { + template + T operator()(const T& lhs, const U& rhs) const noexcept { + return lhs >> rhs; + } +}; + +template +struct SimdReferenceOperatorHelper { + template + void operator()() const { + ex::simd origin_simd(static_cast(3)); + static_assert(noexcept(OpAssign{}(origin_simd[0], static_cast(2)))); + OpAssign{}(origin_simd[0], static_cast(2)); + assert((T)origin_simd[0] == (T)Op{}(static_cast(3), static_cast(std::forward(2)))); + } +}; + +template +struct MaskReferenceOperatorHelper { + template + void operator()() const { + ex::simd_mask origin_mask(true); + static_assert(noexcept(OpAssign{}(origin_mask[0], static_cast(false)))); + OpAssign{}(origin_mask[0], static_cast(false)); + assert((bool)origin_mask[0] == (bool)Op{}(true, static_cast(std::forward(false)))); + } +}; + +template +struct CheckReferenceBitwiseOperators { + template + void operator()() { + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper, AndAssign>()); + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper, OrAssign>()); + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper, XorAssign>()); + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper()); + types::for_each(simd_test_integer_types(), SimdReferenceOperatorHelper()); + + types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper, AndAssign>()); + types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper, OrAssign>()); + types::for_each(simd_test_integer_types(), MaskReferenceOperatorHelper, XorAssign>()); + } +}; + +int main(int, char**) { + types::for_each(types::integer_types(), TestAllSimdAbiFunctor()); + 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; + >; +using simd_test_types = types::concatenate_t>; template