Skip to content

[libc++] <experimental/simd> Add load constructor for class simd/simd_mask #76610

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
Jan 21, 2024

Conversation

joy2myself
Copy link
Member

No description provided.

@joy2myself joy2myself requested a review from a team as a code owner December 30, 2023 08:18
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Dec 30, 2023
@llvmbot
Copy link
Member

llvmbot commented Dec 30, 2023

@llvm/pr-subscribers-libcxx

Author: ZhangYin (joy2myself)

Changes

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

7 Files Affected:

  • (modified) libcxx/include/experimental/__simd/scalar.h (+7)
  • (modified) libcxx/include/experimental/__simd/simd.h (+6)
  • (modified) libcxx/include/experimental/__simd/simd_mask.h (+6)
  • (modified) libcxx/include/experimental/__simd/vec_ext.h (+11)
  • (added) libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp (+105)
  • (added) libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_load.pass.cpp (+55)
  • (modified) libcxx/test/std/experimental/simd/test_utils.h (+12)
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..407dc07fee4d57
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 {
+    constexpr std::size_t alignas_size = alignof(U);
+    alignas(alignas_size) 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 {
+    constexpr std::size_t alignas_size = ex::memory_alignment_v<ex::simd<T, SimdAbi>, U>;
+    alignas(alignas_size) 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 {
+    constexpr std::size_t alignas_size = bit_ceil(sizeof(U) + 1);
+    alignas(alignas_size) 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<alignas_size>());
+    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 U, class T, class Flags, class SimdAbi = ex::simd_abi::compatible<T>, class = void>
+struct has_load_ctor : std::false_type {};
+
+template <class U, class T, class Flags, class SimdAbi>
+struct has_load_ctor<U,
+                     T,
+                     Flags,
+                     SimdAbi,
+                     std::void_t<decltype(ex::simd<T, SimdAbi>(std::declval<const U*>(), Flags()))>> : std::true_type {
+};
+
+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(has_load_ctor<int, T, ex::element_aligned_tag, SimdAbi>::value);
+
+    // is_simd_flag_type_v<Flags> is false
+    static_assert(!has_load_ctor<int, T, int, SimdAbi>::value);
+    static_assert(!has_load_ctor<int, T, SimdAbi, SimdAbi>::value);
+
+    // U is not a vectorizable type.
+    static_assert(!has_load_ctor<SimdAbi, T, ex::element_aligned_tag, SimdAbi>::value);
+    static_assert(!has_load_ctor<ex::element_aligned_tag, T, ex::element_aligned_tag, SimdAbi>::value);
+  }
+};
+
+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..74d20b296b1583
--- /dev/null
+++ b/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_load.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+    constexpr std::size_t element_alignas_size = alignof(bool);
+    alignas(element_alignas_size) 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
+    constexpr std::size_t vector_alignas_size = ex::memory_alignment_v<ex::simd_mask<T, SimdAbi>>;
+    alignas(vector_alignas_size) 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
+    constexpr std::size_t over_alignas_size = bit_ceil(sizeof(bool) + 1);
+    alignas(over_alignas_size) 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<over_alignas_size>());
+    assert_simd_mask_values_equal(overaligned_mask, overaligned_buffer);
+  }
+};
+
+int main(int, char**) {
+  test_all_simd_abi<CheckSimdMaskLoadCtor>();
+  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

@joy2myself
Copy link
Member Author

CI errors fixed by #76611

@joy2myself joy2myself force-pushed the split_simd branch 3 times, most recently from 8bae8c1 to db580a3 Compare December 30, 2023 11:30
@joy2myself
Copy link
Member Author

@philnik777 Any other comments here and for #76611 ?

@joy2myself joy2myself merged commit 6bb5c98 into llvm:main Jan 21, 2024
@maryammo
Copy link
Contributor

maryammo commented Jan 23, 2024

@joy2myself, simd_ctor_load.pass.cpp fails on PowerPC rhel bot with following error

# .---command stderr------------
# | t.tmp.exe: /home/maryammo/llvm-workspace/myFork/llvm-project/libcxx/test/std/experimental/simd/simd.class/../test_utils.h:85: void assert_simd_values_equal(const ex::simd<T, SimdAbi> &, U *) [SimdAbi = std::experimental::simd_abi::__vec_ext<2>, T = long double, U = char]: Assertion `origin_simd[i] == static_cast<T>(expected_value[i])' failed.
# `-----------------------------
# error: command failed with exit status: 250

Could you please take a look? Thanks.

Update : Actually, it seems to be a similar assertion issue as simd_ctor_broadcast.pass.cpp one where it was XFAILed for PowerPC and tracked by this issue.

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.

4 participants