[libcxx-commits] [libcxx] [libc++] <experimental/simd> Add binary operators for class simd (PR #118744)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Dec 4 21:59:12 PST 2024


https://github.com/joy2myself updated https://github.com/llvm/llvm-project/pull/118744

>From 2099ce8d987b464e8d9086296aae8bd875e1859a Mon Sep 17 00:00:00 2001
From: Yin Zhang <zhangyin2018 at iscas.ac.cn>
Date: Mon, 15 Apr 2024 14:43:46 +0800
Subject: [PATCH] [libc++] <experimental/simd> Add binary operators for class
 simd

---
 libcxx/docs/Status/ParallelismProjects.csv    |   1 +
 libcxx/include/experimental/__simd/scalar.h   |  48 ++++
 libcxx/include/experimental/__simd/simd.h     |  50 ++++
 libcxx/include/experimental/__simd/vec_ext.h  |  67 ++++++
 .../simd/simd.nonmembers/simd_binary.pass.cpp | 226 ++++++++++++++++++
 5 files changed, 392 insertions(+)
 create mode 100644 libcxx/test/std/experimental/simd/simd.nonmembers/simd_binary.pass.cpp

diff --git a/libcxx/docs/Status/ParallelismProjects.csv b/libcxx/docs/Status/ParallelismProjects.csv
index fdd6129f926f9e..004e8114ea3d8c 100644
--- a/libcxx/docs/Status/ParallelismProjects.csv
+++ b/libcxx/docs/Status/ParallelismProjects.csv
@@ -31,6 +31,7 @@ Section,Description,Dependencies,Assignee,Complete
 | `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd unary operators <https://github.com/llvm/llvm-project/pull/104764>`_", None, Yin Zhang, |Complete|
 | `[parallel.simd.class] <https://wg21.link/N4808>`_, "Class template simd implementation", None, Yin Zhang, |In Progress|
 | `[parallel.simd.nonmembers] <https://wg21.link/N4808>`_, "simd non-member operations", None, Yin Zhang, |In Progress|
+| `[parallel.simd.nonmembers] <https://wg21.link/N4808>`_, "`simd non-member binary operations <https://github.com/llvm/llvm-project/pull/118744>`_", None, Yin Zhang, |Complete|
 | `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`Class template simd_mask declaration and alias <https://reviews.llvm.org/D144362>`_", [parallel.simd.abi], Yin Zhang, |Complete|
 | `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask<>::size() <https://reviews.llvm.org/D144363>`_", [parallel.simd.class] simd<>::size(), Yin Zhang, |Complete|
 | `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask default constructor <https://github.com/llvm/llvm-project/pull/70424>`_", None, Yin Zhang, |Complete|
diff --git a/libcxx/include/experimental/__simd/scalar.h b/libcxx/include/experimental/__simd/scalar.h
index da318d2f4650fd..a65f55b59dddeb 100644
--- a/libcxx/include/experimental/__simd/scalar.h
+++ b/libcxx/include/experimental/__simd/scalar.h
@@ -82,6 +82,54 @@ struct __simd_operations<_Tp, simd_abi::__scalar> {
   static _LIBCPP_HIDE_FROM_ABI _SimdStorage __unary_minus(_SimdStorage __s) noexcept {
     return {static_cast<_Tp>(-__s.__data)};
   }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __plus(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data + __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __minus(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data - __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __multiplies(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data * __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __divides(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data / __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __modulus(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data % __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __bitwise_and(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data & __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __bitwise_or(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data | __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __bitwise_xor(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data ^ __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __shift_left(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data << __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __shift_right(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data >> __rhs.__data)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __shift_left(_SimdStorage __lhs, int __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data << __rhs)};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __shift_right(_SimdStorage __lhs, int __rhs) noexcept {
+    return {static_cast<_Tp>(__lhs.__data >> __rhs)};
+  }
 };
 
 template <class _Tp>
diff --git a/libcxx/include/experimental/__simd/simd.h b/libcxx/include/experimental/__simd/simd.h
index fd919e75e32f51..80dd91bd299a47 100644
--- a/libcxx/include/experimental/__simd/simd.h
+++ b/libcxx/include/experimental/__simd/simd.h
@@ -37,6 +37,39 @@ class __simd_int_operators<_Simd, _Impl, true> {
   _LIBCPP_HIDE_FROM_ABI _Simd operator~() const noexcept {
     return _Simd(_Impl::__bitwise_not((*static_cast<const _Simd*>(this)).__s_), _Simd::__storage_tag);
   }
+
+  // binary operators for integral _Tp
+  friend _LIBCPP_HIDE_FROM_ABI _Simd operator%(const _Simd& __lhs, const _Simd& __rhs) noexcept {
+    return _Simd(_Impl::__modulus(__lhs.__s_, __rhs.__s_), _Simd::__storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI _Simd operator&(const _Simd& __lhs, const _Simd& __rhs) noexcept {
+    return _Simd(_Impl::__bitwise_and(__lhs.__s_, __rhs.__s_), _Simd::__storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI _Simd operator|(const _Simd& __lhs, const _Simd& __rhs) noexcept {
+    return _Simd(_Impl::__bitwise_or(__lhs.__s_, __rhs.__s_), _Simd::__storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI _Simd operator^(const _Simd& __lhs, const _Simd& __rhs) noexcept {
+    return _Simd(_Impl::__bitwise_xor(__lhs.__s_, __rhs.__s_), _Simd::__storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI _Simd operator<<(const _Simd& __lhs, const _Simd& __rhs) noexcept {
+    return _Simd(_Impl::__shift_left(__lhs.__s_, __rhs.__s_), _Simd::__storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI _Simd operator>>(const _Simd& __lhs, const _Simd& __rhs) noexcept {
+    return _Simd(_Impl::__shift_right(__lhs.__s_, __rhs.__s_), _Simd::__storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI _Simd operator<<(const _Simd& __lhs, int __rhs) noexcept {
+    return _Simd(_Impl::__shift_left(__lhs.__s_, __rhs), _Simd::__storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI _Simd operator>>(const _Simd& __lhs, int __rhs) noexcept {
+    return _Simd(_Impl::__shift_right(__lhs.__s_, __rhs), _Simd::__storage_tag);
+  }
 };
 
 // class template simd [simd.class]
@@ -137,6 +170,23 @@ class simd : public __simd_int_operators<simd<_Tp, _Abi>, __simd_operations<_Tp,
   _LIBCPP_HIDE_FROM_ABI simd operator+() const noexcept { return *this; }
 
   _LIBCPP_HIDE_FROM_ABI simd operator-() const noexcept { return simd(_Impl::__unary_minus(__s_), __storage_tag); }
+
+  // binary operators
+  friend _LIBCPP_HIDE_FROM_ABI simd operator+(const simd& __lhs, const simd& __rhs) noexcept {
+    return simd(_Impl::__plus(__lhs.__s_, __rhs.__s_), __storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI simd operator-(const simd& __lhs, const simd& __rhs) noexcept {
+    return simd(_Impl::__minus(__lhs.__s_, __rhs.__s_), __storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI simd operator*(const simd& __lhs, const simd& __rhs) noexcept {
+    return simd(_Impl::__multiplies(__lhs.__s_, __rhs.__s_), __storage_tag);
+  }
+
+  friend _LIBCPP_HIDE_FROM_ABI simd operator/(const simd& __lhs, const simd& __rhs) noexcept {
+    return simd(_Impl::__divides(__lhs.__s_, __rhs.__s_), __storage_tag);
+  }
 };
 
 template <class _Tp, class _Abi>
diff --git a/libcxx/include/experimental/__simd/vec_ext.h b/libcxx/include/experimental/__simd/vec_ext.h
index abc7e9595be9c8..df46113b678212 100644
--- a/libcxx/include/experimental/__simd/vec_ext.h
+++ b/libcxx/include/experimental/__simd/vec_ext.h
@@ -39,6 +39,8 @@ template <class _Tp, int _Np>
 struct __simd_storage<_Tp, simd_abi::__vec_ext<_Np>> {
   _Tp __data __attribute__((__vector_size__(std::__bit_ceil((sizeof(_Tp) * _Np)))));
 
+  static constexpr bool __is_partial_v = (_Np < (sizeof(__data) / sizeof(_Tp)));
+
   _LIBCPP_HIDE_FROM_ABI _Tp __get(size_t __idx) const noexcept {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < _Np, "Index is out of bounds");
     return __data[__idx];
@@ -47,6 +49,17 @@ struct __simd_storage<_Tp, simd_abi::__vec_ext<_Np>> {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < _Np, "Index is out of bounds");
     __data[__idx] = __v;
   }
+
+  _LIBCPP_HIDE_FROM_ABI __simd_storage __make_padding_nonzero() const noexcept {
+    __simd_storage __result = *this;
+    if constexpr (__is_partial_v) {
+      constexpr size_t __full_size = sizeof(__data) / sizeof(_Tp);
+      for (size_t __i = _Np; __i < __full_size; ++__i) {
+        __result.__data[__i] = _Tp(1);
+      }
+    }
+    return __result;
+  }
 };
 
 template <class _Tp, int _Np>
@@ -97,6 +110,60 @@ struct __simd_operations<_Tp, simd_abi::__vec_ext<_Np>> {
   static _LIBCPP_HIDE_FROM_ABI _SimdStorage __bitwise_not(_SimdStorage __s) noexcept { return {~__s.__data}; }
 
   static _LIBCPP_HIDE_FROM_ABI _SimdStorage __unary_minus(_SimdStorage __s) noexcept { return {-__s.__data}; }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __plus(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {__lhs.__data + __rhs.__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __minus(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {__lhs.__data - __rhs.__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __multiplies(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {__lhs.__data * __rhs.__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __divides(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    if constexpr (!_SimdStorage::__is_partial_v)
+      return {__lhs.__data / __rhs.__data};
+    else
+      return {__lhs.__data / __rhs.__make_padding_nonzero().__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __modulus(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    if constexpr (!_SimdStorage::__is_partial_v)
+      return {__lhs.__data % __rhs.__data};
+    else
+      return {__lhs.__data % __rhs.__make_padding_nonzero().__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __bitwise_and(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {__lhs.__data & __rhs.__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __bitwise_or(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {__lhs.__data | __rhs.__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __bitwise_xor(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {__lhs.__data ^ __rhs.__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __shift_left(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {__lhs.__data << __rhs.__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __shift_right(_SimdStorage __lhs, _SimdStorage __rhs) noexcept {
+    return {__lhs.__data >> __rhs.__data};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __shift_left(_SimdStorage __lhs, int __rhs) noexcept {
+    return {__lhs.__data << __rhs};
+  }
+
+  static _LIBCPP_HIDE_FROM_ABI _SimdStorage __shift_right(_SimdStorage __lhs, int __rhs) noexcept {
+    return {__lhs.__data >> __rhs};
+  }
 };
 
 template <class _Tp, int _Np>
diff --git a/libcxx/test/std/experimental/simd/simd.nonmembers/simd_binary.pass.cpp b/libcxx/test/std/experimental/simd/simd.nonmembers/simd_binary.pass.cpp
new file mode 100644
index 00000000000000..faad7faf0930e4
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.nonmembers/simd_binary.pass.cpp
@@ -0,0 +1,226 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.nonmembers]
+// friend simd operator+(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator-(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator*(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator/(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator%(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator&(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator|(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator^(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator<<(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator>>(const simd& lhs, const simd& rhs) noexcept;
+// friend simd operator<<(const simd& v, int n) noexcept;
+// friend simd operator>>(const simd& v, int n) noexcept;
+
+#include "../test_utils.h"
+#include <experimental/simd>
+
+namespace ex = std::experimental::parallelism_v2;
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorPlus {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd + right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) + static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd + right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorMinus {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd - right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) - static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd - right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorMultiplies {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd * right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) * static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd * right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorDivides {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd / right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) / static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd / right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorModulus {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd % right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) % static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd % right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorBitAnd {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd & right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) & static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd & right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorBitOr {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd | right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) | static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd | right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorBitXor {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd ^ right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) ^ static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd ^ right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorShiftLeft {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd << right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) << static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd << right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorShiftRight {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> left_simd([](T i) { return i; });
+    ex::simd<T, SimdAbi> right_simd(static_cast<T>(2));
+    static_assert(noexcept(left_simd >> right_simd));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) >> static_cast<T>(2);
+    assert_simd_values_equal<array_size>(left_simd >> right_simd, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorShiftLeftByInt {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> simd_value([](T i) { return i; });
+    constexpr int shift_amount = 2;
+    static_assert(noexcept(simd_value << shift_amount));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) << shift_amount;
+    assert_simd_values_equal<array_size>(simd_value << shift_amount, expected_value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdBinaryOperatorShiftRightByInt {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+    ex::simd<T, SimdAbi> simd_value([](T i) { return i; });
+    constexpr int shift_amount = 2;
+    static_assert(noexcept(simd_value >> shift_amount));
+    std::array<T, array_size> expected_value;
+    for (size_t i = 0; i < array_size; ++i)
+      expected_value[i] = static_cast<T>(i) >> shift_amount;
+    assert_simd_values_equal<array_size>(simd_value >> shift_amount, expected_value);
+  }
+};
+
+int main(int, char**) {
+  test_all_simd_abi<CheckSimdBinaryOperatorPlus>();
+  test_all_simd_abi<CheckSimdBinaryOperatorMinus>();
+  test_all_simd_abi<CheckSimdBinaryOperatorMultiplies>();
+  test_all_simd_abi<CheckSimdBinaryOperatorDivides>();
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckSimdBinaryOperatorModulus>());
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckSimdBinaryOperatorBitAnd>());
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckSimdBinaryOperatorBitOr>());
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckSimdBinaryOperatorBitXor>());
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckSimdBinaryOperatorShiftLeft>());
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckSimdBinaryOperatorShiftRight>());
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckSimdBinaryOperatorShiftLeftByInt>());
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckSimdBinaryOperatorShiftRightByInt>());
+  return 0;
+}



More information about the libcxx-commits mailing list