-
Notifications
You must be signed in to change notification settings - Fork 14.2k
[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
Conversation
@llvm/pr-subscribers-libcxx Author: ZhangYin (joy2myself) ChangesFull diff: https://github.com/llvm/llvm-project/pull/76610.diff 7 Files Affected:
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
|
8cde0b1
to
5d3b6b5
Compare
CI errors fixed by #76611 |
libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_ctor_load.pass.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/experimental/simd/simd.class/simd_ctor_load.pass.cpp
Outdated
Show resolved
Hide resolved
8bae8c1
to
db580a3
Compare
@philnik777 Any other comments here and for #76611 ? |
db580a3
to
4d70674
Compare
4d70674
to
065389d
Compare
@joy2myself,
Could you please take a look? Thanks. Update : Actually, it seems to be a similar assertion issue as |
No description provided.