diff --git a/libcxx/include/experimental/simd b/libcxx/include/experimental/simd --- a/libcxx/include/experimental/simd +++ b/libcxx/include/experimental/simd @@ -230,6 +230,7 @@ #include <__assert> // all public C++ headers provide the assertion handler #include <__functional/operations.h> #include +#include #include #include #include @@ -296,9 +297,30 @@ friend void swap(__simd_reference&& __a, value_type& __b) noexcept; }; -struct element_aligned_tag {}; -struct vector_aligned_tag {}; -template struct overaligned_tag {}; +struct element_aligned_tag { + template + static constexpr size_t __alignment = bit_ceil(alignof(_Up)); + template + static constexpr _Up* __apply(_Up* __ptr) { + return static_cast<_Up*>(__builtin_assume_aligned(__ptr, __alignment<_Tp, _Up>)); + } +}; +struct vector_aligned_tag { + template + static constexpr size_t __alignment = bit_ceil(sizeof(_Up) * _Tp::size()); + template + static constexpr _Up* __apply(_Up* __ptr) { + return static_cast<_Up*>(__builtin_assume_aligned(__ptr, __alignment<_Tp, _Up>)); + } +}; +template struct overaligned_tag { + template + static constexpr size_t __alignment = bit_ceil(_Np); + template + static constexpr _Up* __apply(_Up* __ptr) { + return static_cast<_Up*>(__builtin_assume_aligned(__ptr, __alignment<_Tp, _Up>)); + } +}; inline constexpr element_aligned_tag element_aligned{}; inline constexpr vector_aligned_tag vector_aligned{}; template inline constexpr overaligned_tag<_Np> overaligned{}; @@ -320,13 +342,18 @@ template struct is_abi_tag : __is_abi_tag_impl<_Tp> {}; template inline constexpr bool is_abi_tag_v = is_abi_tag<_Tp>::value; -template struct is_simd; +template struct is_simd : false_type {}; +template struct is_simd> : true_type {}; template inline constexpr bool is_simd_v = is_simd<_Tp>::value; -template struct is_simd_mask; +template struct is_simd_mask : false_type {}; +template struct is_simd_mask> : true_type {}; template inline constexpr bool is_simd_mask_v = is_simd_mask<_Tp>::value; -template struct is_simd_flag_type; +template struct is_simd_flag_type : false_type {}; +template<> struct is_simd_flag_type : true_type {}; +template<> struct is_simd_flag_type : true_type {}; +template struct is_simd_flag_type> : true_type {}; template inline constexpr bool is_simd_flag_type_v = is_simd_flag_type<_Tp>::value; template struct __simd_size_impl {}; @@ -337,7 +364,11 @@ template> inline constexpr size_t simd_size_v = simd_size<_Tp, _Abi>::value; -template struct memory_alignment; +template struct __memory_alignment_impl {}; +template struct __memory_alignment_impl<_Tp, _Up, + enable_if_t<(is_simd_v<_Tp> && __is_vectorizable<_Up>()) || (is_simd_mask_v<_Tp> && is_same_v<_Up, bool>)>> + : integral_constant> {}; +template struct memory_alignment : __memory_alignment_impl<_Tp, _Up> {}; template inline constexpr size_t memory_alignment_v = memory_alignment<_Tp, _Up>::value; diff --git a/libcxx/test/std/experimental/simd/simd.traits/is_simd.pass.cpp b/libcxx/test/std/experimental/simd/simd.traits/is_simd.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.traits/is_simd.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// 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.traits] +// template struct ex::is_simd; +// template inline constexpr bool ex::is_simd_v = +// ex::is_simd::value; + +#include "../test_utils.h" +#include +#include + +namespace ex = std::experimental::parallelism_v2; + +struct CheckIsSimdTrue { + template + void operator()() { + static_assert(_Tp::value); + } +}; + +struct CheckIsSimdFalse { + template + void operator()() { + static_assert(!_Tp::value); + } +}; + +struct CheckIsSimdVTrue { + template + void operator()() { + static_assert(_Tp); + } +}; + +struct CheckIsSimdVFalse { + template + void operator()() { + static_assert(!_Tp); + } +}; + +template +void test_simd_abi() {} +template +void test_simd_abi() { + if constexpr (std::is_same::value) { + F{}.template operator()>>(); + } else if constexpr (std::is_same::value) { + F{}.template operator()>(); + F{}.template operator()>>(); + } else if constexpr (std::is_same::value) { + F{}.template operator()>>(); + } else { + F{}.template operator()>(); + F{}.template operator()>>(); + } + + test_simd_abi(); +} + +int main(int, char**) { + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + return 0; +} 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,82 @@ +//===----------------------------------------------------------------------===// +// +// 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.traits] +// template struct is_simd_flag_type; +// template inline constexpr bool ex::is_simd_flag_type_v = ex::is_simd_flag_type::value; + +#include "../test_utils.h" +#include +#include + +namespace ex = std::experimental::parallelism_v2; + +struct CheckIsSimdFlagTypeTrue { + template + void operator()() { + static_assert(_Tp::value); + } +}; + +struct CheckIsSimdFlagTypeFalse { + template + void operator()() { + static_assert(!_Tp::value); + } +}; + +struct CheckIsSimdFlagTypeVTrue { + template + void operator()() { + static_assert(_Tp); + } +}; + +struct CheckIsSimdFlagTypeVFalse { + template + void operator()() { + static_assert(!_Tp); + } +}; + +template +void test_simd_abi() {} +template +void test_simd_abi() { + if constexpr (std::is_same::value) { + F{}.template operator()>(); + F{}.template operator()>(); + F{}.template operator()>>(); + } else if constexpr (std::is_same::value) { + F{}.template operator()>(); + F{}.template operator()>>(); + F{}.template operator()>>(); + } else if constexpr (std::is_same::value) { + F{}.template operator()>(); + F{}.template operator()>(); + F{}.template operator()>>(); + } else { + F{}.template operator()>(); + F{}.template operator()>>(); + F{}.template operator()>>(); + } + + test_simd_abi(); +} + +int main(int, char**) { + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + return 0; +} diff --git a/libcxx/test/std/experimental/simd/simd.traits/is_simd_mask.pass.cpp b/libcxx/test/std/experimental/simd/simd.traits/is_simd_mask.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/experimental/simd/simd.traits/is_simd_mask.pass.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// 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.traits] +// template struct ex::is_simd_mask; +// template inline constexpr bool ex::is_simd_mask_v = ex::is_simd_mask::value; + +#include "../test_utils.h" +#include +#include + +namespace ex = std::experimental::parallelism_v2; + +struct CheckIsSimdMaskTrue { + template + void operator()() { + static_assert(_Tp::value); + } +}; + +struct CheckIsSimdMaskFalse { + template + void operator()() { + static_assert(!_Tp::value); + } +}; + +struct CheckIsSimdMaskVTrue { + template + void operator()() { + static_assert(_Tp); + } +}; + +struct CheckIsSimdMaskVFalse { + template + void operator()() { + static_assert(!_Tp); + } +}; + +template +void test_simd_abi() {} +template +void test_simd_abi() { + if constexpr (std::is_same::value) { + F{}.template operator()>>(); + } else if constexpr (std::is_same::value) { + F{}.template operator()>(); + F{}.template operator()>>(); + } else if constexpr (std::is_same::value) { + F{}.template operator()>>(); + } else { + F{}.template operator()>(); + F{}.template operator()>>(); + } + + test_simd_abi(); +} + +int main(int, char**) { + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + 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,97 @@ +//===----------------------------------------------------------------------===// +// +// 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.traits] +// template struct memory_alignment; +// template +// inline constexpr size_t memory_alignment_v = memory_alignment::value; + +#include "../test_utils.h" +#include + +namespace ex = std::experimental::parallelism_v2; + +struct CheckMemoryAlignmentNative { + template + void operator()() { + static_assert(ex::memory_alignment>{}.value == _LIBCPP_NATIVE_SIMD_WIDTH_IN_BYTES); + static_assert(ex::memory_alignment_v> == _LIBCPP_NATIVE_SIMD_WIDTH_IN_BYTES); + } +}; +struct CheckMemoryAlignmentCompatible { + template + void operator()() { + static_assert(ex::memory_alignment>{}.value == 16); + static_assert(ex::memory_alignment_v> == 16); + } +}; +struct CheckMemoryAlignmentScalar { + template + void operator()() { + static_assert(ex::memory_alignment>{}.value == sizeof(_Tp)); + static_assert(ex::memory_alignment_v> == sizeof(_Tp)); + } +}; + +struct CheckMemoryAlignmentFixedSize { + template + void operator()() { + static_assert(ex::memory_alignment>{}.value == std::bit_ceil(sizeof(_Tp) * _Np)); + static_assert(ex::memory_alignment_v> == std::bit_ceil(sizeof(_Tp) * _Np)); + } +}; + +struct CheckMemoryAlignmentDeduce { + template + void operator()() { + static_assert(ex::memory_alignment>{}.value == std::bit_ceil(sizeof(_Tp) * _Np)); + static_assert(ex::memory_alignment_v> == std::bit_ceil(sizeof(_Tp) * _Np)); + } +}; +struct CheckMemoryAlignmentMask { + template + void operator()() { + static_assert(ex::memory_alignment>{}.value == + std::bit_ceil(sizeof(bool) * ex::simd_size_v<_Tp, SimdAbi>)); + static_assert(ex::memory_alignment_v> == + std::bit_ceil(sizeof(bool) * ex::simd_size_v<_Tp, SimdAbi>)); + } +}; +template +void test_simd_abi() {} +template +void test_simd_abi() { + if constexpr (std::is_same_v) { + F{}.template operator()<_Tp, ex::simd_abi::native<_Tp>, _Np>(); + } else if constexpr (std::is_same_v) { + F{}.template operator()<_Tp, ex::simd_abi::compatible<_Tp>, _Np>(); + } else if constexpr (std::is_same_v) { + F{}.template operator()<_Tp, ex::simd_abi::scalar, _Np>(); + } else if constexpr (std::is_same_v) { + F{}.template operator()<_Tp, ex::simd_abi::fixed_size<_Np>, _Np>(); + } else if constexpr (std::is_same_v) { + F{}.template operator()<_Tp, ex::simd_abi::deduce_t<_Tp, _Np>, _Np>(); + } else { + F{}.template operator()<_Tp, SimdAbi, _Np>(); + } + test_simd_abi(); +} + +int main(int, char**) { + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + test_all_simd_abi(); + return 0; +}