mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-24 15:06:06 +00:00
[libc++] <experimental/simd> Add load constructor for class simd/simd_mask (#76610)
This commit is contained in:
parent
a70d3101ba
commit
6bb5c989bd
@ -22,6 +22,7 @@ Section,Description,Dependencies,Assignee,Complete
|
||||
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd broadcast constructor <https://reviews.llvm.org/D156225>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd implicit type conversion constructor <https://github.com/llvm/llvm-project/pull/71132>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd generate constructor <https://reviews.llvm.org/D159442>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd load constructor <https://github.com/llvm/llvm-project/pull/76610>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "`simd subscript operators <https://github.com/llvm/llvm-project/pull/68960>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.class] <https://wg21.link/N4808>`_, "Class template simd implementation", None, Yin Zhang, |In Progress|
|
||||
| `[parallel.simd.nonmembers] <https://wg21.link/N4808>`_, "simd non-member operations", None, Yin Zhang, |In Progress|
|
||||
@ -30,6 +31,7 @@ Section,Description,Dependencies,Assignee,Complete
|
||||
| `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask default constructor <https://github.com/llvm/llvm-project/pull/70424>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask broadcast constructor <https://reviews.llvm.org/D156225>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask implicit type conversion constructor <https://github.com/llvm/llvm-project/pull/71132>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask load constructor <https://github.com/llvm/llvm-project/pull/76610>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "`simd_mask subscript operators <https://github.com/llvm/llvm-project/pull/68960>`_", None, Yin Zhang, |Complete|
|
||||
| `[parallel.simd.mask.class] <https://wg21.link/N4808>`_, "Class template simd_mask implementation", None, Yin Zhang, |In Progress|
|
||||
| `[parallel.simd.mask.nonmembers] <https://wg21.link/N4808>`_, "simd_mask non-member operations", None, Yin Zhang, |In Progress|
|
||||
|
|
@ -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
|
||||
|
@ -64,6 +64,12 @@ public:
|
||||
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); }
|
||||
|
@ -52,6 +52,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// 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); }
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,92 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user