diff --git a/libcxx/docs/Status/ParallelismProjects.csv b/libcxx/docs/Status/ParallelismProjects.csv --- a/libcxx/docs/Status/ParallelismProjects.csv +++ b/libcxx/docs/Status/ParallelismProjects.csv @@ -17,6 +17,7 @@ | `[parallel.simd.class] `_, "`Class template simd declaration and alias `_", [parallel.simd.abi], Yin Zhang, |Complete| | `[parallel.simd.class] `_, "`simd<>::size() `_", [parallel.simd.traits] simd_size[_v], Yin Zhang, |Complete| | `[parallel.simd.class] `_, "`simd broadcast constructor `_", None, Yin Zhang, |Complete| +| `[parallel.simd.class] `_, "`simd generate constructor `_", None, Yin Zhang, |Complete| | `[parallel.simd.class] `_, "Class template simd implementation", None, Yin Zhang, |In Progress| | `[parallel.simd.nonmembers] `_, "simd non-member operations", None, Yin Zhang, |In Progress| | `[parallel.simd.mask.class] `_, "`Class template simd_mask declaration and alias `_", [parallel.simd.abi], Yin Zhang, |Complete| diff --git a/libcxx/include/experimental/__simd/scalar.h b/libcxx/include/experimental/__simd/scalar.h --- a/libcxx/include/experimental/__simd/scalar.h +++ b/libcxx/include/experimental/__simd/scalar.h @@ -46,6 +46,11 @@ using _MaskStorage = __mask_storage<_Tp, simd_abi::__scalar>; static _LIBCPP_HIDE_FROM_ABI _SimdStorage __broadcast(_Tp __v) noexcept { return {__v}; } + + template + static _LIBCPP_HIDE_FROM_ABI _SimdStorage __generate(_Generator&& __g) noexcept { + return {__g(std::integral_constant())}; + } }; template diff --git a/libcxx/include/experimental/__simd/simd.h b/libcxx/include/experimental/__simd/simd.h --- a/libcxx/include/experimental/__simd/simd.h +++ b/libcxx/include/experimental/__simd/simd.h @@ -44,6 +44,10 @@ template >, int> = 0> _LIBCPP_HIDE_FROM_ABI simd(_Up&& __v) noexcept : __s_(_Impl::__broadcast(static_cast(__v))) {} + // generator constructor + template , int> = 0> + explicit _LIBCPP_HIDE_FROM_ABI simd(_Generator&& __g) : __s_(_Impl::__generate(std::forward<_Generator>(__g))) {} + // scalar access [simd.subscr] // Add operator[] temporarily to test braodcast. Add test for it in later patch. _LIBCPP_HIDE_FROM_ABI value_type operator[](size_t __i) const { return __s_.__get(__i); } diff --git a/libcxx/include/experimental/__simd/utility.h b/libcxx/include/experimental/__simd/utility.h --- a/libcxx/include/experimental/__simd/utility.h +++ b/libcxx/include/experimental/__simd/utility.h @@ -19,6 +19,7 @@ #include <__type_traits/is_volatile.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> +#include <__utility/integer_sequence.h> #include #include @@ -71,6 +72,25 @@ (!__is_vectorizable_v<_Up> && is_convertible_v<_Up, _Tp>) || is_same_v<_Up, int> || (is_same_v<_Up, unsigned int> && is_unsigned_v<_Tp>); +template +inline constexpr bool __is_well_formed = false; + +template +inline constexpr bool + __is_well_formed<_Tp, + _Generator, + _Idx, + std::void_t()(integral_constant()))>> = + __can_broadcast_v<_Tp, decltype(std::declval<_Generator>()(integral_constant()))>; + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __can_generate(index_sequence<_Idxes...>) { + return (true && ... && __is_well_formed<_Tp, _Generator, _Idxes>); +} + +template +inline constexpr bool __can_generate_v = experimental::__can_generate<_Tp, _Generator>(make_index_sequence<_Size>()); + } // namespace parallelism_v2 _LIBCPP_END_NAMESPACE_EXPERIMENTAL diff --git a/libcxx/include/experimental/__simd/vec_ext.h b/libcxx/include/experimental/__simd/vec_ext.h --- a/libcxx/include/experimental/__simd/vec_ext.h +++ b/libcxx/include/experimental/__simd/vec_ext.h @@ -11,6 +11,7 @@ #define _LIBCPP_EXPERIMENTAL___SIMD_VEC_EXT_H #include <__bit/bit_ceil.h> +#include <__utility/forward.h> #include #include #include @@ -56,6 +57,16 @@ } return __result; } + + template + static _LIBCPP_HIDE_FROM_ABI _SimdStorage __generate_init(_Generator&& __g, std::index_sequence<_Is...>) { + return _SimdStorage{{__g(std::integral_constant())...}}; + } + + template + static _LIBCPP_HIDE_FROM_ABI _SimdStorage __generate(_Generator&& __g) noexcept { + return __generate_init(std::forward<_Generator>(__g), std::make_index_sequence<_Np>()); + } }; template diff --git a/libcxx/test/std/experimental/simd/simd.class/simd_ctor_generator.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_generator.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.class/simd_ctor_generator.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// +// +// [simd.class] +// template explicit simd(G&& gen) noexcept; + +#include "../test_utils.h" +#include + +namespace ex = std::experimental::parallelism_v2; + +template +struct CheckGenerateSimdCtor { + template + void operator()() { + ex::simd origin_simd([](T i) { return i; }); + constexpr size_t array_size = origin_simd.size(); + std::array expected_value; + for (size_t i = 0; i < array_size; ++i) + expected_value[i] = static_cast(i); + assert_simd_values_equal(origin_simd, expected_value); + } +}; + +template , class = void> +struct has_generate_ctor : std::false_type {}; + +template +struct has_generate_ctor(std::declval()))>> + : std::true_type {}; + +template +struct CheckGenerateCtorTraits { + template + void operator()() { + static_assert(!has_generate_ctor::value); + + auto func = [](T i) { return i; }; + static_assert(has_generate_ctor::value); + } +}; + +int main(int, char**) { + test_all_simd_abi(); + test_all_simd_abi(); + return 0; +}