[libcxx-commits] [libcxx] [libc++] <experimental/simd> Add assignment operator of simd reference (PR #70020)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Oct 24 02:50:02 PDT 2023


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

>From 3acc9023e485e88e86b94ae3dd30d99279eb1fb4 Mon Sep 17 00:00:00 2001
From: Zhangyin <zhangyin2018 at iscas.ac.cn>
Date: Mon, 25 Sep 2023 17:25:37 +0800
Subject: [PATCH] [libc++] <experimental/simd> Add assignment operator of simd
 reference

---
 libcxx/docs/Status/ParallelismProjects.csv    |   1 +
 .../include/experimental/__simd/reference.h   |   7 ++
 libcxx/include/experimental/__simd/utility.h  |   8 ++
 .../reference_assignment.pass.cpp             | 101 ++++++++++++++++++
 .../test/std/experimental/simd/test_utils.h   |   8 ++
 5 files changed, 125 insertions(+)
 create mode 100644 libcxx/test/std/experimental/simd/simd.reference/reference_assignment.pass.cpp

diff --git a/libcxx/docs/Status/ParallelismProjects.csv b/libcxx/docs/Status/ParallelismProjects.csv
index 667a74d207c9363..05a66080823d421 100644
--- a/libcxx/docs/Status/ParallelismProjects.csv
+++ b/libcxx/docs/Status/ParallelismProjects.csv
@@ -15,6 +15,7 @@ Section,Description,Dependencies,Assignee,Complete
 | `[parallel.simd.traits] <https://wg21.link/N4808>`_, "simd type traits resize_simd", None, Yin Zhang, |In Progress|
 | `[parallel.simd.whereexpr] <https://wg21.link/N4808>`_, "Where expression class templates", None, Yin Zhang, |In Progress|
 | `[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.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 broadcast constructor <https://reviews.llvm.org/D156225>`_", None, Yin Zhang, |Complete|
diff --git a/libcxx/include/experimental/__simd/reference.h b/libcxx/include/experimental/__simd/reference.h
index 335b127bf271fad..987871056c704dd 100644
--- a/libcxx/include/experimental/__simd/reference.h
+++ b/libcxx/include/experimental/__simd/reference.h
@@ -44,6 +44,13 @@ class __simd_reference {
   __simd_reference(const __simd_reference&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI operator value_type() const noexcept { return __get(); }
+
+  template <class _Up>
+  _LIBCPP_HIDE_FROM_ABI std::enable_if_t<__reference_well_formed<value_type, _Up>, __simd_reference>
+  operator=(_Up&& __v) && noexcept {
+    __set(static_cast<value_type>(std::forward<_Up>(__v)));
+    return {__s_, __idx_};
+  }
 };
 
 } // namespace parallelism_v2
diff --git a/libcxx/include/experimental/__simd/utility.h b/libcxx/include/experimental/__simd/utility.h
index 847d006629c8d3b..7092450a56bae08 100644
--- a/libcxx/include/experimental/__simd/utility.h
+++ b/libcxx/include/experimental/__simd/utility.h
@@ -91,6 +91,14 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __can_generate(index_sequence<_Idxes...>) {
 template <class _Tp, class _Generator, std::size_t _Size>
 inline constexpr bool __can_generate_v = experimental::__can_generate<_Tp, _Generator>(make_index_sequence<_Size>());
 
+template <class _Tp, class _Up, class = void>
+inline constexpr bool __reference_well_formed = false;
+
+template <class _Tp, class _Up>
+inline constexpr bool
+    __reference_well_formed<_Tp, _Up, std::void_t<decltype(declval<_Tp&>() = std::forward<_Up>(declval<_Up&&>()))>> =
+        true;
+
 } // namespace parallelism_v2
 _LIBCPP_END_NAMESPACE_EXPERIMENTAL
 
diff --git a/libcxx/test/std/experimental/simd/simd.reference/reference_assignment.pass.cpp b/libcxx/test/std/experimental/simd/simd.reference/reference_assignment.pass.cpp
new file mode 100644
index 000000000000000..a6375fa4272e7f0
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.reference/reference_assignment.pass.cpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// 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;
+
+#include "../test_utils.h"
+#include <experimental/simd>
+
+namespace ex = std::experimental::parallelism_v2;
+
+template <class T, class SimdAbi>
+struct CheckSimdReferenceAssignmentHelper {
+  template <class U>
+  void operator()() const {
+    if constexpr (reference_well_formed<T, U>) {
+      ex::simd<T, SimdAbi> origin_simd([](T i) { return i; });
+      for (size_t i = 0; i < origin_simd.size(); ++i) {
+        origin_simd[i] = static_cast<U>(i + 1);
+        assert(origin_simd[i] == static_cast<T>(std::forward<U>(i + 1)));
+      }
+    }
+  }
+};
+
+template <class T, class SimdAbi>
+struct CheckMaskReferenceAssignmentHelper {
+  template <class U>
+  void operator()() const {
+    if constexpr (reference_well_formed<bool, U>) {
+      ex::simd_mask<T, SimdAbi> origin_mask(true);
+      for (size_t i = 0; i < origin_mask.size(); ++i) {
+        origin_mask[i] = static_cast<U>(i % 2);
+        assert(origin_mask[i] == static_cast<T>(std::forward<U>(i % 2)));
+      }
+    }
+  }
+};
+
+template <class U, class T, class SimdAbi = ex::simd_abi::compatible<T>, class = void>
+struct has_simd_ref_assignment : std::false_type {};
+
+template <class U, class T, class SimdAbi>
+struct has_simd_ref_assignment<
+    U,
+    T,
+    SimdAbi,
+    std::void_t<decltype(std::declval<typename ex::simd<T, SimdAbi>::reference&&>() = std::declval<U&&>())>>
+    : std::true_type {};
+
+template <class U, class T, class SimdAbi = ex::simd_abi::compatible<T>, class = void>
+struct has_mask_ref_assignment : std::false_type {};
+
+template <class U, class T, class SimdAbi>
+struct has_mask_ref_assignment<
+    U,
+    T,
+    SimdAbi,
+    std::void_t<decltype(std::declval<typename ex::simd<T, SimdAbi>::reference&&>() = std::declval<U&&>())>>
+    : std::true_type {};
+
+template <class T, class SimdAbi>
+struct CheckReferenceAssignmentTraitsHelper {
+  template <class U>
+  void operator()() const {
+    if constexpr (reference_well_formed<T, U>)
+      static_assert(has_simd_ref_assignment<U, T, SimdAbi>::value);
+    else
+      static_assert(!has_simd_ref_assignment<U, T, SimdAbi>::value);
+
+    if constexpr (reference_well_formed<bool, U>)
+      static_assert(has_mask_ref_assignment<U, T, SimdAbi>::value);
+    else
+      static_assert(!has_mask_ref_assignment<U, T, SimdAbi>::value);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckReferenceAssignment {
+  template <class SimdAbi>
+  void operator()() {
+    types::for_each(arithmetic_no_bool_types(), CheckSimdReferenceAssignmentHelper<T, SimdAbi>());
+    types::for_each(arithmetic_no_bool_types(), CheckMaskReferenceAssignmentHelper<T, SimdAbi>());
+
+    types::for_each(arithmetic_no_bool_types(), CheckReferenceAssignmentTraitsHelper<T, SimdAbi>());
+  }
+};
+
+int main(int, char**) {
+  test_all_simd_abi<CheckReferenceAssignment>();
+  return 0;
+}
diff --git a/libcxx/test/std/experimental/simd/test_utils.h b/libcxx/test/std/experimental/simd/test_utils.h
index a478a43a87271cf..32f9eb907568fbb 100644
--- a/libcxx/test/std/experimental/simd/test_utils.h
+++ b/libcxx/test/std/experimental/simd/test_utils.h
@@ -65,6 +65,14 @@ inline constexpr bool is_non_narrowing_convertible_v = false;
 template <class From, class To>
 inline constexpr bool is_non_narrowing_convertible_v<From, To, std::void_t<decltype(To{std::declval<From>()})>> = true;
 
+template <class T, class U, class = void>
+inline constexpr bool reference_well_formed = false;
+
+template <class T, class U>
+inline constexpr bool
+    reference_well_formed<T, U, std::void_t<decltype(std::declval<T&>() = std::forward<U>(std::declval<U&&>()))>> =
+        true;
+
 template <std::size_t ArraySize, class SimdAbi, class T, class U = T>
 void assert_simd_values_equal(const ex::simd<T, SimdAbi>& origin_simd, const std::array<U, ArraySize>& expected_value) {
   for (std::size_t i = 0; i < origin_simd.size(); ++i)



More information about the libcxx-commits mailing list