Skip to content

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;
+}

@github-actions
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
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