Skip to content

[libc++] <experimental/simd> Add compound assignment operators for simd reference #86761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 4, 2024

Conversation

joy2myself
Copy link
Member

No description provided.

@joy2myself joy2myself requested a review from a team as a code owner March 27, 2024 03:03
@joy2myself joy2myself marked this pull request as draft March 27, 2024 03:03
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 27, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 27, 2024

@llvm/pr-subscribers-libcxx

Author: ZhangYin (joy2myself)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/86761.diff

2 Files Affected:

  • (modified) libcxx/include/experimental/__simd/reference.h (+20)
  • (added) libcxx/test/std/experimental/simd/simd.reference/reference_operators.pass.cpp (+106)
diff --git a/libcxx/include/experimental/__simd/reference.h b/libcxx/include/experimental/__simd/reference.h
index 7efbba96ec71b1..ea8a3742901274 100644
--- a/libcxx/include/experimental/__simd/reference.h
+++ b/libcxx/include/experimental/__simd/reference.h
@@ -55,6 +55,26 @@ class __simd_reference {
     __set(static_cast<value_type>(std::forward<_Up>(__v)));
     return {__s_, __idx_};
   }
+
+#  define _LIBCXX_SIMD_REFERENCE_OP_(__op)                                                                             \
+    template <class _Up>                                                                                               \
+    enable_if_t<is_void_v<void_t<decltype(std::declval<value_type&>() __op## = std::declval<_Up>())>>,                 \
+                __simd_reference> _LIBCPP_HIDE_FROM_ABI                                                                \
+    operator __op##=(_Up&& __v)&& noexcept {                                                                           \
+      __set(__get() __op static_cast<value_type>(std::forward<_Up>(__v)));                                             \
+      return {__s_, __idx_};                                                                                           \
+    }
+  _LIBCXX_SIMD_REFERENCE_OP_(+)
+  _LIBCXX_SIMD_REFERENCE_OP_(-)
+  _LIBCXX_SIMD_REFERENCE_OP_(*)
+  _LIBCXX_SIMD_REFERENCE_OP_(/)
+  _LIBCXX_SIMD_REFERENCE_OP_(%)
+  _LIBCXX_SIMD_REFERENCE_OP_(&)
+  _LIBCXX_SIMD_REFERENCE_OP_(|)
+  _LIBCXX_SIMD_REFERENCE_OP_(^)
+  _LIBCXX_SIMD_REFERENCE_OP_(<<)
+  _LIBCXX_SIMD_REFERENCE_OP_(>>)
+#  undef _LIBCXX_SIMD_REFERENCE_OP_
 };
 
 } // namespace parallelism_v2
diff --git a/libcxx/test/std/experimental/simd/simd.reference/reference_operators.pass.cpp b/libcxx/test/std/experimental/simd/simd.reference/reference_operators.pass.cpp
new file mode 100644
index 00000000000000..c6b5003ad49092
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.reference/reference_operators.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// 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;
+// 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>
+#include <iostream>
+
+namespace ex = std::experimental::parallelism_v2;
+
+#define LIBCXX_SIMD_REFERENCE_OP_(op, name)                                                                            \
+  template <class T, class SimdAbi>                                                                                    \
+  struct SimdReferenceOperatorHelper##name {                                                                           \
+    template <class U>                                                                                                 \
+    void operator()() const {                                                                                          \
+      ex::simd<T, SimdAbi> origin_simd(2);                                                                             \
+      for (size_t i = 0; i < origin_simd.size(); ++i) {                                                                \
+        static_assert(noexcept(origin_simd[i] op## = static_cast<U>(i + 1)));                                          \
+        origin_simd[i] op## = static_cast<U>(i + 1);                                                                   \
+        assert((T)origin_simd[i] == (T)(static_cast<T>(2) op static_cast<T>(std::forward<U>(i + 1))));                 \
+      }                                                                                                                \
+    }                                                                                                                  \
+  };
+LIBCXX_SIMD_REFERENCE_OP_(+, Plus)
+LIBCXX_SIMD_REFERENCE_OP_(-, Minus)
+LIBCXX_SIMD_REFERENCE_OP_(*, Multiplies)
+LIBCXX_SIMD_REFERENCE_OP_(/, Divides)
+LIBCXX_SIMD_REFERENCE_OP_(%, Modulus)
+LIBCXX_SIMD_REFERENCE_OP_(&, BitAnd)
+LIBCXX_SIMD_REFERENCE_OP_(|, BitOr)
+LIBCXX_SIMD_REFERENCE_OP_(^, BitXor)
+LIBCXX_SIMD_REFERENCE_OP_(<<, ShiftLeft)
+LIBCXX_SIMD_REFERENCE_OP_(>>, ShiftRight)
+#undef LIBCXX_SIMD_REFERENCE_OP_
+
+#define LIBCXX_SIMD_MASK_REFERENCE_OP_(op, name)                                                                       \
+  template <class T, class SimdAbi>                                                                                    \
+  struct MaskReferenceOperatorHelper##name {                                                                           \
+    template <class U>                                                                                                 \
+    void operator()() const {                                                                                          \
+      ex::simd<T, SimdAbi> origin_simd_mask(true);                                                                     \
+      for (size_t i = 0; i < origin_simd_mask.size(); ++i) {                                                           \
+        static_assert(noexcept(origin_simd_mask[i] op## = static_cast<U>(i % 2)));                                     \
+        origin_simd_mask[i] op## = static_cast<U>(i % 2);                                                              \
+        assert((bool)origin_simd_mask[i] == (bool)(true op static_cast<bool>(std::forward<U>(i % 2))));                \
+      }                                                                                                                \
+    }                                                                                                                  \
+  };
+LIBCXX_SIMD_MASK_REFERENCE_OP_(&, BitAnd)
+LIBCXX_SIMD_MASK_REFERENCE_OP_(|, BitOr)
+LIBCXX_SIMD_MASK_REFERENCE_OP_(^, BitXor)
+#undef LIBCXX_SIMD_MASK_REFERENCE_OP_
+
+template <class T, std::size_t>
+struct CheckReferenceArithOperators {
+  template <class SimdAbi>
+  void operator()() {
+    types::for_each(simd_test_types(), SimdReferenceOperatorHelperPlus<T, SimdAbi>());
+    types::for_each(simd_test_types(), SimdReferenceOperatorHelperMinus<T, SimdAbi>());
+    types::for_each(simd_test_types(), SimdReferenceOperatorHelperMultiplies<T, SimdAbi>());
+    types::for_each(simd_test_types(), SimdReferenceOperatorHelperDivides<T, SimdAbi>());
+  }
+};
+
+template <class T, std::size_t>
+struct CheckReferenceIntOperators {
+  template <class SimdAbi>
+  void operator()() {
+    types::for_each(types::integer_types(), SimdReferenceOperatorHelperModulus<T, SimdAbi>());
+    types::for_each(types::integer_types(), SimdReferenceOperatorHelperBitAnd<T, SimdAbi>());
+    types::for_each(types::integer_types(), SimdReferenceOperatorHelperBitOr<T, SimdAbi>());
+    types::for_each(types::integer_types(), SimdReferenceOperatorHelperBitXor<T, SimdAbi>());
+    types::for_each(types::integer_types(), SimdReferenceOperatorHelperShiftLeft<T, SimdAbi>());
+    types::for_each(types::integer_types(), SimdReferenceOperatorHelperShiftRight<T, SimdAbi>());
+
+    types::for_each(types::integer_types(), MaskReferenceOperatorHelperBitAnd<T, SimdAbi>());
+    types::for_each(types::integer_types(), MaskReferenceOperatorHelperBitOr<T, SimdAbi>());
+    types::for_each(types::integer_types(), MaskReferenceOperatorHelperBitXor<T, SimdAbi>());
+  }
+};
+
+int main(int, char**) {
+  test_all_simd_abi<CheckReferenceArithOperators>();
+  types::for_each(types::integer_types(), TestAllSimdAbiFunctor<CheckReferenceIntOperators>());
+  return 0;
+}

Copy link

github-actions bot commented Mar 27, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@joy2myself joy2myself force-pushed the reference_op branch 13 times, most recently from c3eab8e to 9156a42 Compare April 8, 2024 05:23
@joy2myself joy2myself marked this pull request as ready for review April 8, 2024 08:01
@joy2myself joy2myself force-pushed the reference_op branch 3 times, most recently from 22a86a8 to 964c86f Compare April 8, 2024 10:58
@joy2myself
Copy link
Member Author

@philnik777 Hi! This and the other two patches (#86478, #88091) are ready for review.

@joy2myself
Copy link
Member Author

@philnik777 Any comments here and #88091?

The CI errors don't seem related.

@joy2myself
Copy link
Member Author

@philnik777 Gentle ping.

@joy2myself
Copy link
Member Author

Hi @philnik777,

Just following up on this PR and #88091. Could you please take a look when you get a chance?

I have some follow-up patches ready, but they may depend on these currently open PRs. It would be great if these two PRs could be merged soon.

Thanks!

Copy link
Contributor

@philnik777 philnik777 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the slow review, I didn't have a lot of time recently.

@joy2myself joy2myself force-pushed the reference_op branch 2 times, most recently from fe8a3bb to 7665eb8 Compare July 31, 2024 02:59
@joy2myself
Copy link
Member Author

@philnik777 Hello, I have removed all macro definitions according to your comment. However, the compiler does not allow lambda expressions to be passed directly into the template, so I use struct to wrap lambda expressions to pass template parameters in test files.

In addition, due to the error of insufficient memory or flash capacity in ARMv7 CI, I split the test cases into two test files.

Any other comments?

@joy2myself joy2myself requested a review from philnik777 August 2, 2024 06:57
@joy2myself joy2myself merged commit 899055f into llvm:main Aug 4, 2024
54 of 56 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants