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 @@ -4,12 +4,13 @@ | `[parallel.alg] <https://wg21.link/N4808>`_, "Parallel algorithms", None, unassigned, |Not Started| | `[parallel.taskblock] <https://wg21.link/N4808>`_, "Task Block", None, unassigned, |Not Started| | `[parallel.simd.abi] <https://wg21.link/N4808>`_, "`simd ABI tags <https://reviews.llvm.org/D144362>`_", [parallel.simd.class] [parallel.simd.mask.class] declarations and alias, Yin Zhang, |Complete| +| `[parallel.simd.synopsis] <https://wg21.link/N4808>`_, "`simd aligned tags <https://reviews.llvm.org/D153319>`_", [parallel.simd.class] [parallel.simd.mask.class] declarations, Yin Zhang, |Complete| | `[parallel.simd.traits] <https://wg21.link/N4808>`_, "`simd type traits is_abi_tag[_v] <https://reviews.llvm.org/D144362>`_", [parallel.simd.abi], Yin Zhang, |Complete| | `[parallel.simd.traits] <https://wg21.link/N4808>`_, "`simd type traits is_simd[_v] <https://reviews.llvm.org/D144362>`_", [parallel.simd.class] declaration and alias, Yin Zhang, |Complete| | `[parallel.simd.traits] <https://wg21.link/N4808>`_, "`simd type traits is_simd_mask[_v] <https://reviews.llvm.org/D144362>`_", [parallel.simd.mask.class] declaration and alias, Yin Zhang, |Complete| | `[parallel.simd.traits] <https://wg21.link/N4808>`_, "simd type traits is_simd_flag_type", None, Yin Zhang, |In Progress| | `[parallel.simd.traits] <https://wg21.link/N4808>`_, "`simd type traits simd_size[_v] <https://reviews.llvm.org/D144363>`_", [parallel.simd.traits] is_abi_tag[_v], Yin Zhang, |Complete| -| `[parallel.simd.traits] <https://wg21.link/N4808>`_, "simd type traits memory_alignment", None, Yin Zhang, |In Progress| +| `[parallel.simd.traits] <https://wg21.link/N4808>`_, "`simd type traits memory_alignment <https://reviews.llvm.org/D153319>`_", [parallel.simd.aligned] simd aligned tags, Yin Zhang, |Complete| | `[parallel.simd.traits] <https://wg21.link/N4808>`_, "simd type traits rebind_simd", None, Yin Zhang, |In Progress| | `[parallel.simd.traits] <https://wg21.link/N4808>`_, "simd type traits resize_simd", None, Yin Zhang, |In Progress| | `[parallel.simd.whereexpr] <https://wg21.link/N4808>`_, "Where expression class templates", None, Yin Zhang, |In Progress| diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -904,6 +904,7 @@ experimental/__config experimental/__memory experimental/__simd/abi_tag.h + experimental/__simd/aligned_tag.h experimental/__simd/declaration.h experimental/__simd/scalar.h experimental/__simd/simd.h diff --git a/libcxx/include/__bit/bit_ceil.h b/libcxx/include/__bit/bit_ceil.h --- a/libcxx/include/__bit/bit_ceil.h +++ b/libcxx/include/__bit/bit_ceil.h @@ -21,13 +21,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER >= 20 +#if _LIBCPP_STD_VER >= 17 -template <__libcpp_unsigned_integer _Tp> -_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_ceil(_Tp __t) noexcept { +template <class _Tp> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Tp __bit_ceil(_Tp __t) noexcept { if (__t < 2) return 1; - const unsigned __n = numeric_limits<_Tp>::digits - std::countl_zero((_Tp)(__t - 1u)); + const unsigned __n = numeric_limits<_Tp>::digits - std::__countl_zero((_Tp)(__t - 1u)); _LIBCPP_ASSERT_UNCATEGORIZED(__n != numeric_limits<_Tp>::digits, "Bad input to bit_ceil"); if constexpr (sizeof(_Tp) >= sizeof(unsigned)) @@ -39,7 +39,15 @@ } } -#endif // _LIBCPP_STD_VER >= 20 +# if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_ceil(_Tp __t) noexcept { + return std::__bit_ceil(__t); +} + +# endif // _LIBCPP_STD_VER >= 20 +#endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__memory/assume_aligned.h b/libcxx/include/__memory/assume_aligned.h --- a/libcxx/include/__memory/assume_aligned.h +++ b/libcxx/include/__memory/assume_aligned.h @@ -22,16 +22,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER >= 20 - template <size_t _Np, class _Tp> -[[nodiscard]] -_LIBCPP_HIDE_FROM_ABI -constexpr _Tp* assume_aligned(_Tp* __ptr) { +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __assume_aligned(_Tp* __ptr) { static_assert(_Np != 0 && (_Np & (_Np - 1)) == 0, "std::assume_aligned<N>(p) requires N to be a power of two"); - if (is_constant_evaluated()) { + if (__libcpp_is_constant_evaluated()) { return __ptr; } else { _LIBCPP_ASSERT_UNCATEGORIZED(reinterpret_cast<uintptr_t>(__ptr) % _Np == 0, "Alignment assumption is violated"); @@ -39,6 +35,13 @@ } } +#if _LIBCPP_STD_VER >= 20 + +template <size_t _Np, class _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp* assume_aligned(_Tp* __ptr) { + return std::__assume_aligned<_Np>(__ptr); +} + #endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/experimental/__simd/aligned_tag.h b/libcxx/include/experimental/__simd/aligned_tag.h new file mode 100644 --- /dev/null +++ b/libcxx/include/experimental/__simd/aligned_tag.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_EXPERIMENTAL___SIMD_ALIGNED_TAG_H +#define _LIBCPP_EXPERIMENTAL___SIMD_ALIGNED_TAG_H + +#include <__bit/bit_ceil.h> +#include <__memory/assume_aligned.h> +#include <cstdint> + +#if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL +inline namespace parallelism_v2 { +// memory alignment +struct element_aligned_tag { + template <class _Tp, class _Up = typename _Tp::value_type> + static constexpr size_t __alignment = alignof(_Up); + + template <class _Tp, class _Up> + static _LIBCPP_HIDE_FROM_ABI constexpr _Up* __apply(_Up* __ptr) { + return __ptr; + } +}; + +struct vector_aligned_tag { + template <class _Tp, class _Up = typename _Tp::value_type> + static constexpr size_t __alignment = std::__bit_ceil(sizeof(_Up) * _Tp::size()); + + template <class _Tp, class _Up> + static _LIBCPP_HIDE_FROM_ABI constexpr _Up* __apply(_Up* __ptr) { + return std::__assume_aligned<__alignment<_Tp, _Up>, _Up>(__ptr); + } +}; + +template <size_t _Np> +struct overaligned_tag { + template <class _Tp, class _Up = typename _Tp::value_type> + static constexpr size_t __alignment = _Np; + + template <class _Tp, class _Up> + static _LIBCPP_HIDE_FROM_ABI constexpr _Up* __apply(_Up* __ptr) { + return std::__assume_aligned<__alignment<_Tp, _Up>, _Up>(__ptr); + } +}; + +inline constexpr element_aligned_tag element_aligned{}; + +inline constexpr vector_aligned_tag vector_aligned{}; + +template <size_t _Np> +inline constexpr overaligned_tag<_Np> overaligned{}; + +} // namespace parallelism_v2 +_LIBCPP_END_NAMESPACE_EXPERIMENTAL + +#endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) +#endif // _LIBCPP_EXPERIMENTAL___SIMD_ALIGNED_TAG_H diff --git a/libcxx/include/experimental/__simd/traits.h b/libcxx/include/experimental/__simd/traits.h --- a/libcxx/include/experimental/__simd/traits.h +++ b/libcxx/include/experimental/__simd/traits.h @@ -11,6 +11,7 @@ #define _LIBCPP_EXPERIMENTAL___SIMD_TRAITS_H #include <experimental/__simd/abi_tag.h> +#include <experimental/__simd/aligned_tag.h> #include <experimental/__simd/declaration.h> #include <experimental/__simd/utility.h> @@ -50,6 +51,21 @@ template <class _Tp> struct is_simd_mask : bool_constant<is_simd_mask_v<_Tp>> {}; +template <class _Tp> +inline constexpr bool is_simd_flag_type_v = false; + +template <> +inline constexpr bool is_simd_flag_type_v<element_aligned_tag> = true; + +template <> +inline constexpr bool is_simd_flag_type_v<vector_aligned_tag> = true; + +template <size_t _Np> +inline constexpr bool is_simd_flag_type_v<overaligned_tag<_Np>> = true; + +template <class _Tp> +struct is_simd_flag_type : bool_constant<is_simd_flag_type_v<_Tp>> {}; + template <class _Tp, class _Abi = simd_abi::compatible<_Tp>, bool = (__is_vectorizable_v<_Tp> && is_abi_tag_v<_Abi>)> struct simd_size : integral_constant<size_t, _Abi::__simd_size> {}; @@ -59,6 +75,17 @@ template <class _Tp, class _Abi = simd_abi::compatible<_Tp>> inline constexpr size_t simd_size_v = simd_size<_Tp, _Abi>::value; +template <class _Tp, + class _Up = typename _Tp::value_type, + bool = (is_simd_v<_Tp> && __is_vectorizable_v<_Up>) || (is_simd_mask_v<_Tp> && is_same_v<_Up, bool>)> +struct memory_alignment : integral_constant<size_t, vector_aligned_tag::__alignment<_Tp, _Up>> {}; + +template <class _Tp, class _Up> +struct memory_alignment<_Tp, _Up, false> {}; + +template <class _Tp, class _Up = typename _Tp::value_type> +inline constexpr size_t memory_alignment_v = memory_alignment<_Tp, _Up>::value; + } // namespace parallelism_v2 _LIBCPP_END_NAMESPACE_EXPERIMENTAL 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 @@ -12,6 +12,7 @@ #include <__type_traits/is_arithmetic.h> #include <__type_traits/is_const.h> +#include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_same.h> #include <__type_traits/is_volatile.h> diff --git a/libcxx/include/experimental/simd b/libcxx/include/experimental/simd --- a/libcxx/include/experimental/simd +++ b/libcxx/include/experimental/simd @@ -37,6 +37,14 @@ template <class T> using native_simd_mask = simd_mask<T, simd_abi::native<T>>; template <class T, int N> using fixed_size_simd_mask = simd_mask<T, simd_abi::fixed_size<N>>; + // memory alignment + struct element_aligned_tag {}; + struct vector_aligned_tag {}; + template <size_t> struct overaligned_tag {}; + inline constexpr element_aligned_tag element_aligned{}; + inline constexpr vector_aligned_tag vector_aligned{}; + template <size_t N> inline constexpr overaligned_tag<N> overaligned{}; + // traits [simd.traits] template<class T> struct is_abi_tag; template<class T> inline constexpr bool is_abi_tag_v = is_abi_tag<T>::value; @@ -47,10 +55,17 @@ template <class T> struct is_simd_mask; template <class T> inline constexpr bool is_simd_mask_v = is_simd_mask<T>::value; + template<class T> struct is_simd_flag_type; + template<class T> inline constexpr bool is_simd_flag_type_v = is_simd_flag_type<T>::value; + template<class T, class Abi = simd_abi::compatible<T>> struct simd_size; template<class T, class Abi = simd_abi::compatible<T>> inline constexpr size_t simd_size_v = simd_size<T,Abi>::value; + template<class T, class U = typename T::value_type> struct memory_alignment; + template<class T, class U = typename T::value_type> + inline constexpr size_t memory_alignment_v = memory_alignment<T,U>::value; + } // namespace parallelism_v2 } // namespace std::experimental @@ -64,6 +79,8 @@ #include <experimental/__config> #include <experimental/__simd/abi_tag.h> +#include <experimental/__simd/aligned_tag.h> +#include <experimental/__simd/declaration.h> #include <experimental/__simd/scalar.h> #include <experimental/__simd/simd.h> #include <experimental/__simd/simd_mask.h> diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -265,6 +265,8 @@ experimental/set experimental/memory_resource experimental/set set experimental/simd cstddef +experimental/simd cstdint +experimental/simd limits experimental/string experimental/memory_resource experimental/string string experimental/unordered_map algorithm diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -266,6 +266,8 @@ experimental/set experimental/memory_resource experimental/set set experimental/simd cstddef +experimental/simd cstdint +experimental/simd limits experimental/string experimental/memory_resource experimental/string string experimental/unordered_map algorithm diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -266,6 +266,8 @@ experimental/set experimental/memory_resource experimental/set set experimental/simd cstddef +experimental/simd cstdint +experimental/simd limits experimental/string experimental/memory_resource experimental/string string experimental/type_traits initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -266,6 +266,8 @@ experimental/set experimental/memory_resource experimental/set set experimental/simd cstddef +experimental/simd cstdint +experimental/simd limits experimental/string experimental/memory_resource experimental/string string experimental/type_traits initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -272,6 +272,8 @@ experimental/set experimental/memory_resource experimental/set set experimental/simd cstddef +experimental/simd cstdint +experimental/simd limits experimental/string experimental/memory_resource experimental/string string experimental/type_traits initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -185,6 +185,8 @@ experimental/set experimental/memory_resource experimental/set set experimental/simd cstddef +experimental/simd cstdint +experimental/simd limits experimental/string experimental/memory_resource experimental/string string experimental/type_traits initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -185,6 +185,8 @@ experimental/set experimental/memory_resource experimental/set set experimental/simd cstddef +experimental/simd cstdint +experimental/simd limits experimental/string experimental/memory_resource experimental/string string experimental/type_traits initializer_list diff --git a/libcxx/test/std/experimental/simd/simd.traits/is_simd_flag_type.pass.cpp b/libcxx/test/std/experimental/simd/simd.traits/is_simd_flag_type.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.traits/is_simd_flag_type.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// 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.traits] +// template <class T> struct is_simd_flag_type; +// template <class T> inline constexpr bool ex::is_simd_flag_type_v = ex::is_simd_flag_type<T>::value; + +#include "../test_utils.h" + +namespace ex = std::experimental::parallelism_v2; + +template <class T, std::size_t N> +struct CheckIsSimdFlagType { + template <class SimdAbi> + void operator()() { + static_assert(ex::is_simd_flag_type<ex::element_aligned_tag>::value); + static_assert(ex::is_simd_flag_type<ex::vector_aligned_tag>::value); + static_assert(ex::is_simd_flag_type<ex::overaligned_tag<N>>::value); + + static_assert(!ex::is_simd_flag_type<T>::value); + static_assert(!ex::is_simd_flag_type<ex::simd<T, SimdAbi>>::value); + static_assert(!ex::is_simd_flag_type<ex::simd_mask<T, SimdAbi>>::value); + + static_assert(ex::is_simd_flag_type_v<ex::element_aligned_tag>); + static_assert(ex::is_simd_flag_type_v<ex::vector_aligned_tag>); + static_assert(ex::is_simd_flag_type_v<ex::overaligned_tag<N>>); + + static_assert(!ex::is_simd_flag_type_v<T>); + static_assert(!ex::is_simd_flag_type_v<ex::simd<T, SimdAbi>>); + static_assert(!ex::is_simd_flag_type_v<ex::simd_mask<T, SimdAbi>>); + } +}; + +int main(int, char**) { + test_all_simd_abi<CheckIsSimdFlagType>(); + return 0; +} diff --git a/libcxx/test/std/experimental/simd/simd.traits/memory_alignment.pass.cpp b/libcxx/test/std/experimental/simd/simd.traits/memory_alignment.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.traits/memory_alignment.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// 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.traits] +// template <class T, class U = typename T::value_type> struct memory_alignment; +// template <class T, class U = typename T::value_type> +// inline constexpr std::size_t memory_alignment_v = memory_alignment<T, U>::value; + +#include "../test_utils.h" + +namespace ex = std::experimental::parallelism_v2; + +template <class T, std::size_t N> +struct CheckMemoryAlignmentMask { + template <class SimdAbi> + void operator()() { + LIBCPP_STATIC_ASSERT( + ex::memory_alignment<ex::simd_mask<T, SimdAbi>>::value == bit_ceil(sizeof(bool) * ex::simd_size_v<T, SimdAbi>)); + LIBCPP_STATIC_ASSERT( + ex::memory_alignment_v<ex::simd_mask<T, SimdAbi>> == bit_ceil(sizeof(bool) * ex::simd_size_v<T, SimdAbi>)); + } +}; + +template <class T, std::size_t N> +struct CheckMemoryAlignmentLongDouble { + template <class SimdAbi> + void operator()() { + if constexpr (std::is_same_v<T, long double>) { + // on i686-w64-mingw32-clang++, the size of long double is 12 bytes. Disambiguation is needed. + static_assert( + ex::memory_alignment<ex::simd<T, SimdAbi>>::value == bit_ceil(sizeof(T) * ex::simd_size_v<T, SimdAbi>)); + static_assert(ex::memory_alignment_v<ex::simd<T, SimdAbi>> == bit_ceil(sizeof(T) * ex::simd_size_v<T, SimdAbi>)); + } + } +}; + +struct CheckMemAlignmentFixedDeduce { + template <class T, std::size_t N> + void check() { + if constexpr (!std::is_same_v<T, long double>) { + static_assert(ex::memory_alignment_v<ex::simd<T, ex::simd_abi::fixed_size<N>>> == sizeof(T) * bit_ceil(N), + "Memory Alignment mismatch with abi fixed_size"); + static_assert(ex::memory_alignment<ex::simd<T, ex::simd_abi::fixed_size<N>>>::value == sizeof(T) * bit_ceil(N), + "Memory Alignment mismatch with abi fixed_size"); + + static_assert(ex::memory_alignment_v<ex::simd<T, ex::simd_abi::deduce_t<T, N>>> == sizeof(T) * bit_ceil(N), + "Memory Alignment mismatch with abi deduce"); + static_assert(ex::memory_alignment<ex::simd<T, ex::simd_abi::deduce_t<T, N>>>::value == sizeof(T) * bit_ceil(N), + "Memory Alignment mismatch with abi deduce"); + } + } + + template <class T, std::size_t... N> + void performChecks(std::index_sequence<N...>) { + (check<T, N + 1>(), ...); + } + + template <class T> + void operator()() { + performChecks<T>(std::make_index_sequence<max_simd_size>{}); + } +}; + +struct CheckMemAlignmentScalarNativeCompatible { + template <class T> + void operator()() { + if constexpr (!std::is_same_v<T, long double>) { + static_assert(ex::memory_alignment<ex::simd<T, ex::simd_abi::scalar>>::value == sizeof(T)); + static_assert(ex::memory_alignment_v<ex::simd<T, ex::simd_abi::scalar>> == sizeof(T)); + + LIBCPP_STATIC_ASSERT(ex::memory_alignment<ex::simd<T, ex::simd_abi::compatible<T>>>::value == 16); + LIBCPP_STATIC_ASSERT(ex::memory_alignment_v<ex::simd<T, ex::simd_abi::compatible<T>>> == 16); + + LIBCPP_STATIC_ASSERT( + ex::memory_alignment<ex::simd<T, ex::simd_abi::native<T>>>::value == _LIBCPP_NATIVE_SIMD_WIDTH_IN_BYTES); + LIBCPP_STATIC_ASSERT( + ex::memory_alignment_v<ex::simd<T, ex::simd_abi::native<T>>> == _LIBCPP_NATIVE_SIMD_WIDTH_IN_BYTES); + } + } +}; + +template <class T, class U = typename T::value_type, class = void> +struct has_memory_alignment : std::false_type {}; + +template <class T, class U> +struct has_memory_alignment<T, U, std::void_t<decltype(ex::memory_alignment<T, U>::value)>> : std::true_type {}; + +struct CheckMemoryAlignmentTraits { + template <class T> + void operator()() { + static_assert(has_memory_alignment<ex::native_simd<T>>::value); + static_assert(has_memory_alignment<ex::fixed_size_simd_mask<T, 4>>::value); + static_assert(has_memory_alignment<ex::native_simd<T>, T>::value); + static_assert(has_memory_alignment<ex::fixed_size_simd_mask<T, 4>, bool>::value); + + static_assert(!has_memory_alignment<T, T>::value); + static_assert(!has_memory_alignment<T, bool>::value); + static_assert(!has_memory_alignment<ex::native_simd<T>, bool>::value); + static_assert(!has_memory_alignment<ex::fixed_size_simd_mask<T, 4>, T>::value); + } +}; + +int main(int, char**) { + types::for_each(arithmetic_no_bool_types(), CheckMemAlignmentFixedDeduce()); + types::for_each(arithmetic_no_bool_types(), CheckMemAlignmentScalarNativeCompatible()); + test_all_simd_abi<CheckMemoryAlignmentMask>(); + test_all_simd_abi<CheckMemoryAlignmentLongDouble>(); + types::for_each(arithmetic_no_bool_types(), CheckMemoryAlignmentTraits()); + return 0; +} diff --git a/libcxx/test/std/experimental/simd/simd.traits/memory_alignment.verify.cpp b/libcxx/test/std/experimental/simd/simd.traits/memory_alignment.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.traits/memory_alignment.verify.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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.traits] +// template <class T, class U = typename T::value_type> struct memory_alignment; +// template <class T, class U = typename T::value_type> +// inline constexpr std::size_t memory_alignment_v = memory_alignment<T, U>::value; + +#include <experimental/simd> + +namespace ex = std::experimental::parallelism_v2; + +int main(int, char**) { + (void)ex::memory_alignment<ex::native_simd<bool>, bool>::value; + // expected-error-re@* {{no member named 'value' in {{.*}}}} + (void)ex::memory_alignment<int, int>::value; + // expected-error-re@* {{no member named 'value' in {{.*}}}} + (void)ex::memory_alignment<ex::native_simd_mask<int>, int>::value; + // expected-error-re@* {{no member named 'value' in {{.*}}}} + (void)ex::memory_alignment<ex::native_simd<int>, bool>::value; + // expected-error-re@* {{no member named 'value' in {{.*}}}} + + (void)ex::memory_alignment_v<ex::native_simd<bool>, bool>; + // expected-error-re@* {{no member named 'value' in {{.*}}}} + (void)ex::memory_alignment_v<int, int>; + // expected-error-re@* {{no member named 'value' in {{.*}}}} + (void)ex::memory_alignment_v<ex::native_simd_mask<int>, int>; + // expected-error-re@* {{no member named 'value' in {{.*}}}} + (void)ex::memory_alignment_v<ex::native_simd<int>, bool>; + // expected-error-re@* {{no member named 'value' in {{.*}}}} + + return 0; +} diff --git a/libcxx/test/std/experimental/simd/test_utils.h b/libcxx/test/std/experimental/simd/test_utils.h --- a/libcxx/test/std/experimental/simd/test_utils.h +++ b/libcxx/test/std/experimental/simd/test_utils.h @@ -43,4 +43,11 @@ types::for_each(arithmetic_no_bool_types(), TestAllSimdAbiFunctor<Func>()); } +constexpr size_t bit_ceil(size_t val) { + size_t pow = 1; + while (pow < val) + pow <<= 1; + return pow; +} + #endif // TEST_UTIL_H