[libcxx-commits] [libcxx] [libc++] <experimental/simd> Add load constructor for class simd/simd_mask (PR #76610)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Dec 30 03:30:13 PST 2023


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

>From 8bae8c13b0aa995a1569699bc4b4805d2fa2e585 Mon Sep 17 00:00:00 2001
From: Yin Zhang <zhangyin2018 at iscas.ac.cn>
Date: Wed, 8 Nov 2023 12:31:22 +0800
Subject: [PATCH] [libc++] <experimental/simd> Add load constructor for class
 simd/simd_mask

---
 libcxx/include/experimental/__simd/scalar.h   |  7 ++
 libcxx/include/experimental/__simd/simd.h     |  6 ++
 .../include/experimental/__simd/simd_mask.h   |  6 ++
 libcxx/include/experimental/__simd/vec_ext.h  | 11 +++
 .../simd/simd.class/simd_ctor_load.pass.cpp   | 91 +++++++++++++++++++
 .../simd_mask_ctor_load.pass.cpp              | 67 ++++++++++++++
 .../test/std/experimental/simd/test_utils.h   | 12 +++
 7 files changed, 200 insertions(+)
 create mode 100644 libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp
 create mode 100644 libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_load.pass.cpp

diff --git a/libcxx/include/experimental/__simd/scalar.h b/libcxx/include/experimental/__simd/scalar.h
index 5eeff4c1e82a38..717fd6cd92d710 100644
--- a/libcxx/include/experimental/__simd/scalar.h
+++ b/libcxx/include/experimental/__simd/scalar.h
@@ -56,6 +56,11 @@ struct __simd_operations<_Tp, simd_abi::__scalar> {
   static _LIBCPP_HIDE_FROM_ABI _SimdStorage __generate(_Generator&& __g) noexcept {
     return {__g(std::integral_constant<size_t, 0>())};
   }
+
+  template <class _Up>
+  static _LIBCPP_HIDE_FROM_ABI void __load(_SimdStorage& __s, const _Up* __mem) noexcept {
+    __s.__data = static_cast<_Tp>(__mem[0]);
+  }
 };
 
 template <class _Tp>
@@ -63,6 +68,8 @@ struct __mask_operations<_Tp, simd_abi::__scalar> {
   using _MaskStorage = __mask_storage<_Tp, simd_abi::__scalar>;
 
   static _LIBCPP_HIDE_FROM_ABI _MaskStorage __broadcast(bool __v) noexcept { return {__v}; }
+
+  static _LIBCPP_HIDE_FROM_ABI void __load(_MaskStorage& __s, const bool* __mem) noexcept { __s.__data = __mem[0]; }
 };
 
 } // namespace parallelism_v2
diff --git a/libcxx/include/experimental/__simd/simd.h b/libcxx/include/experimental/__simd/simd.h
index c345811fee7fc7..db4ebb8e4a381b 100644
--- a/libcxx/include/experimental/__simd/simd.h
+++ b/libcxx/include/experimental/__simd/simd.h
@@ -64,6 +64,12 @@ class simd {
   explicit _LIBCPP_HIDE_FROM_ABI simd(_Generator&& __g) noexcept
       : __s_(_Impl::__generate(std::forward<_Generator>(__g))) {}
 
+  // load constructor
+  template <class _Up, class _Flags, enable_if_t<__is_vectorizable_v<_Up> && is_simd_flag_type_v<_Flags>, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI simd(const _Up* __mem, _Flags) {
+    _Impl::__load(__s_, _Flags::template __apply<simd>(__mem));
+  }
+
   // scalar access [simd.subscr]
   _LIBCPP_HIDE_FROM_ABI reference operator[](size_t __i) noexcept { return reference(__s_, __i); }
   _LIBCPP_HIDE_FROM_ABI value_type operator[](size_t __i) const noexcept { return __s_.__get(__i); }
diff --git a/libcxx/include/experimental/__simd/simd_mask.h b/libcxx/include/experimental/__simd/simd_mask.h
index db03843b46e3ad..754db7992683b1 100644
--- a/libcxx/include/experimental/__simd/simd_mask.h
+++ b/libcxx/include/experimental/__simd/simd_mask.h
@@ -52,6 +52,12 @@ class simd_mask {
     }
   }
 
+  // load constructor
+  template <class _Flags, enable_if_t<is_simd_flag_type_v<_Flags>, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI simd_mask(const value_type* __mem, _Flags) {
+    _Impl::__load(__s_, _Flags::template __apply<simd_mask>(__mem));
+  }
+
   // scalar access [simd.mask.subscr]
   _LIBCPP_HIDE_FROM_ABI reference operator[](size_t __i) noexcept { return reference(__s_, __i); }
   _LIBCPP_HIDE_FROM_ABI value_type operator[](size_t __i) const noexcept { return __s_.__get(__i); }
diff --git a/libcxx/include/experimental/__simd/vec_ext.h b/libcxx/include/experimental/__simd/vec_ext.h
index 07ba032f493b1e..7883132ba6c0db 100644
--- a/libcxx/include/experimental/__simd/vec_ext.h
+++ b/libcxx/include/experimental/__simd/vec_ext.h
@@ -73,6 +73,12 @@ struct __simd_operations<_Tp, simd_abi::__vec_ext<_Np>> {
   static _LIBCPP_HIDE_FROM_ABI _SimdStorage __generate(_Generator&& __g) noexcept {
     return __generate_init(std::forward<_Generator>(__g), std::make_index_sequence<_Np>());
   }
+
+  template <class _Up>
+  static _LIBCPP_HIDE_FROM_ABI void __load(_SimdStorage& __s, const _Up* __mem) noexcept {
+    for (size_t __i = 0; __i < _Np; __i++)
+      __s.__data[__i] = static_cast<_Tp>(__mem[__i]);
+  }
 };
 
 template <class _Tp, int _Np>
@@ -87,6 +93,11 @@ struct __mask_operations<_Tp, simd_abi::__vec_ext<_Np>> {
     }
     return __result;
   }
+
+  static _LIBCPP_HIDE_FROM_ABI void __load(_MaskStorage& __s, const bool* __mem) noexcept {
+    for (size_t __i = 0; __i < _Np; __i++)
+      __s.__data[__i] = experimental::__set_all_bits<_Tp>(__mem[__i]);
+  }
 };
 
 } // namespace parallelism_v2
diff --git a/libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp
new file mode 100644
index 00000000000000..1f335bcc9f3164
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.class]
+// template<class U, class Flags> simd(const U* mem, Flags);
+
+#include "../test_utils.h"
+
+namespace ex = std::experimental::parallelism_v2;
+
+template <class T, class SimdAbi, std::size_t array_size>
+struct ElementAlignedLoadCtorHelper {
+  template <class U>
+  void operator()() const {
+    U buffer[array_size];
+    for (size_t i = 0; i < array_size; ++i)
+      buffer[i] = static_cast<U>(i);
+    ex::simd<T, SimdAbi> origin_simd(buffer, ex::element_aligned_tag());
+    assert_simd_values_equal(origin_simd, buffer);
+  }
+};
+
+template <class T, class SimdAbi, std::size_t array_size>
+struct VectorAlignedLoadCtorHelper {
+  template <class U>
+  void operator()() const {
+    alignas(ex::memory_alignment_v<ex::simd<T, SimdAbi>, U>) U buffer[array_size];
+    for (size_t i = 0; i < array_size; ++i)
+      buffer[i] = static_cast<U>(i);
+    ex::simd<T, SimdAbi> origin_simd(buffer, ex::vector_aligned_tag());
+    assert_simd_values_equal(origin_simd, buffer);
+  }
+};
+
+template <class T, class SimdAbi, std::size_t array_size>
+struct OveralignedLoadCtorHelper {
+  template <class U>
+  void operator()() const {
+    alignas(bit_ceil(sizeof(U) + 1)) U buffer[array_size];
+    for (size_t i = 0; i < array_size; ++i)
+      buffer[i] = static_cast<U>(i);
+    ex::simd<T, SimdAbi> origin_simd(buffer, ex::overaligned_tag<bit_ceil(sizeof(U) + 1)>());
+    assert_simd_values_equal(origin_simd, buffer);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckSimdLoadCtor {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+
+    types::for_each(arithmetic_no_bool_types(), ElementAlignedLoadCtorHelper<T, SimdAbi, array_size>());
+    types::for_each(arithmetic_no_bool_types(), VectorAlignedLoadCtorHelper<T, SimdAbi, array_size>());
+    types::for_each(arithmetic_no_bool_types(), OveralignedLoadCtorHelper<T, SimdAbi, array_size>());
+  }
+};
+
+template <class T, std::size_t>
+struct CheckLoadCtorTraits {
+  template <class SimdAbi>
+  void operator()() {
+    // This function shall not participate in overload resolution unless
+    // is_simd_flag_type_v<Flags> is true, and
+    // U is a vectorizable type.
+    static_assert(std::is_constructible_v<ex::simd<T, SimdAbi>, const int*, ex::element_aligned_tag>);
+
+    // is_simd_flag_type_v<Flags> is false
+    static_assert(!std::is_constructible_v<ex::simd<T, SimdAbi>, const int*, T>);
+    static_assert(!std::is_constructible_v<ex::simd<T, SimdAbi>, const int*, SimdAbi>);
+
+    // U is not a vectorizable type.
+    static_assert(!std::is_constructible_v<ex::simd<T, SimdAbi>, const SimdAbi*, ex::element_aligned_tag>);
+    static_assert(!std::is_constructible_v<ex::simd<T, SimdAbi>, const ex::element_aligned_tag*, ex::element_aligned_tag>);
+  }
+};
+
+int main(int, char**) {
+  test_all_simd_abi<CheckSimdLoadCtor>();
+  test_all_simd_abi<CheckLoadCtorTraits>();
+  return 0;
+}
diff --git a/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_load.pass.cpp b/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_load.pass.cpp
new file mode 100644
index 00000000000000..e59c38a2e6c4ba
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_load.pass.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.class]
+// template<class Flags> simd_mask(const value_type* mem, Flags);
+
+#include "../test_utils.h"
+
+namespace ex = std::experimental::parallelism_v2;
+
+template <class T, std::size_t>
+struct CheckSimdMaskLoadCtor {
+  template <class SimdAbi>
+  void operator()() {
+    constexpr std::size_t array_size = ex::simd_size_v<T, SimdAbi>;
+
+    // element aligned tag
+    bool element_buffer[array_size];
+    for (size_t i = 0; i < array_size; ++i)
+      element_buffer[i] = static_cast<bool>(i % 2);
+    ex::simd_mask<T, SimdAbi> element_mask(element_buffer, ex::element_aligned_tag());
+    assert_simd_mask_values_equal(element_mask, element_buffer);
+
+    // vector aligned tag
+    alignas(ex::memory_alignment_v<ex::simd_mask<T, SimdAbi>>) bool vector_buffer[array_size];
+    for (size_t i = 0; i < array_size; ++i)
+      vector_buffer[i] = static_cast<bool>(i % 2);
+    ex::simd_mask<T, SimdAbi> vector_mask(vector_buffer, ex::vector_aligned_tag());
+    assert_simd_mask_values_equal(vector_mask, vector_buffer);
+
+    // overaligned tag
+    alignas(bit_ceil(sizeof(bool) + 1)) bool overaligned_buffer[array_size];
+    for (size_t i = 0; i < array_size; ++i)
+      overaligned_buffer[i] = static_cast<bool>(i % 2);
+    ex::simd_mask<T, SimdAbi> overaligned_mask(overaligned_buffer, ex::overaligned_tag<bit_ceil(sizeof(bool) + 1)>());
+    assert_simd_mask_values_equal(overaligned_mask, overaligned_buffer);
+  }
+};
+
+template <class T, std::size_t>
+struct CheckMaskLoadCtorTraits {
+  template <class SimdAbi>
+  void operator()() {
+    // This function shall not participate in overload resolution unless
+    // is_simd_flag_type_v<Flags> is true
+    static_assert(std::is_constructible_v<ex::simd_mask<T, SimdAbi>, const bool*, ex::element_aligned_tag>);
+
+    // is_simd_flag_type_v<Flags> is false
+    static_assert(!std::is_constructible_v<ex::simd_mask<T, SimdAbi>, const bool*, T>);
+    static_assert(!std::is_constructible_v<ex::simd_mask<T, SimdAbi>, const bool*, SimdAbi>);
+  }
+};
+
+int main(int, char**) {
+  test_all_simd_abi<CheckSimdMaskLoadCtor>();
+  test_all_simd_abi<CheckMaskLoadCtorTraits>();
+  return 0;
+}
diff --git a/libcxx/test/std/experimental/simd/test_utils.h b/libcxx/test/std/experimental/simd/test_utils.h
index 30a48521aa589c..b3679b51e50b50 100644
--- a/libcxx/test/std/experimental/simd/test_utils.h
+++ b/libcxx/test/std/experimental/simd/test_utils.h
@@ -79,4 +79,16 @@ void assert_simd_mask_values_equal(const ex::simd_mask<T, SimdAbi>& origin_mask,
     assert(origin_mask[i] == expected_value[i]);
 }
 
+template <class SimdAbi, class T, class U = T>
+void assert_simd_values_equal(const ex::simd<T, SimdAbi>& origin_simd, U* expected_value) {
+  for (size_t i = 0; i < origin_simd.size(); ++i)
+    assert(origin_simd[i] == static_cast<T>(expected_value[i]));
+}
+
+template <class SimdAbi, class T>
+void assert_simd_mask_values_equal(const ex::simd_mask<T, SimdAbi>& origin_mask, bool* expected_value) {
+  for (size_t i = 0; i < origin_mask.size(); ++i)
+    assert(origin_mask[i] == expected_value[i]);
+}
+
 #endif // LIBCXX_TEST_STD_EXPERIMENTAL_SIMD_TEST_UTILS_H



More information about the libcxx-commits mailing list