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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libcxx/docs/Status/ParallelismProjects.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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|
Expand All @@ -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|
7 changes: 7 additions & 0 deletions libcxx/include/experimental/__simd/scalar.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,20 @@ 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>
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
Expand Down
6 changes: 6 additions & 0 deletions libcxx/include/experimental/__simd/simd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down
6 changes: 6 additions & 0 deletions libcxx/include/experimental/__simd/simd_mask.h
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
Expand Down
11 changes: 11 additions & 0 deletions libcxx/include/experimental/__simd/vec_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
12 changes: 12 additions & 0 deletions libcxx/test/std/experimental/simd/test_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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