[libcxx-commits] [libcxx] [libc++] <experimental/simd> Add compound assignment operators for simd reference (PR #86761)
via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jul 31 23:59:26 PDT 2024
https://github.com/joy2myself updated https://github.com/llvm/llvm-project/pull/86761
>From 85f719836fb44178f6750c8eeceb111a18ede917 Mon Sep 17 00:00:00 2001
From: Yin Zhang <zhangyin2018 at iscas.ac.cn>
Date: Tue, 9 Jan 2024 17:04:16 +0800
Subject: [PATCH] [libc++] <experimental/simd> Add compound assignment
operators for simd reference
---
libcxx/docs/Status/ParallelismProjects.csv | 1 +
.../include/experimental/__simd/reference.h | 81 ++++++++++++
.../reference_arith_operators.pass.cpp | 95 +++++++++++++++
.../reference_bitwise_operators.pass.cpp | 115 ++++++++++++++++++
.../test/std/experimental/simd/test_utils.h | 11 +-
5 files changed, 298 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 06087e3d870f9..d5186094610c6 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 af61dbcc2fe92..8a3e87d5efa8e 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,86 @@ class __simd_reference {
template <class _Tp1, class _Storage1, class _Vp1>
friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept;
+
+ template <
+ class _Up,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() + std::declval<_Up>())&&>, int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() - std::declval<_Up>())&&>, int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() * std::declval<_Up>())&&>, int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() / std::declval<_Up>())&&>, int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() % std::declval<_Up>())&&>, int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() & std::declval<_Up>())&&>, int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() | std::declval<_Up>())&&>, int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() ^ std::declval<_Up>())&&>, int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() << std::declval<_Up>())&&>,
+ int> = 0>
+ _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,
+ enable_if_t<is_assignable_v<value_type&, decltype(std::declval<value_type&>() >> std::declval<_Up>())&&>,
+ int> = 0>
+ _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 0000000000000..2a4a1346db0bc
--- /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 0000000000000..340b92c4006dc
--- /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 9b44160857513..3c227a43c2f4d 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() {
More information about the libcxx-commits
mailing list