diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 255a0474c0f6b..f6fcfa3fa8ed2 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -714,6 +714,10 @@ set(files __ranges/view_interface.h __ranges/views.h __ranges/zip_view.h + __simd/abi.h + __simd/basic_simd.h + __simd/basic_simd_mask.h + __simd/simd_flags.h __split_buffer __std_mbstate_t.h __stop_token/atomic_unique_lock.h @@ -863,6 +867,7 @@ set(files __type_traits/maybe_const.h __type_traits/nat.h __type_traits/negation.h + __type_traits/pack_utils.h __type_traits/promote.h __type_traits/rank.h __type_traits/remove_all_extents.h @@ -875,6 +880,7 @@ set(files __type_traits/remove_reference.h __type_traits/remove_volatile.h __type_traits/result_of.h + __type_traits/standard_types.h __type_traits/strip_signature.h __type_traits/type_identity.h __type_traits/type_list.h @@ -1029,6 +1035,7 @@ set(files semaphore set shared_mutex + simd source_location span sstream diff --git a/libcxx/include/__simd/abi.h b/libcxx/include/__simd/abi.h new file mode 100644 index 0000000000000..7f54b02a05de8 --- /dev/null +++ b/libcxx/include/__simd/abi.h @@ -0,0 +1,165 @@ +//===----------------------------------------------------------------------===// +// +// 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___SIMD_ABI_H +#define _LIBCPP___SIMD_ABI_H + +#include <__concepts/convertible_to.h> +#include <__concepts/equality_comparable.h> +#include <__config> +#include <__cstddef/size_t.h> +#include <__type_traits/standard_types.h> +#include <__utility/integer_sequence.h> +#include + +#if _LIBCPP_STD_VER >= 26 + +_LIBCPP_BEGIN_NAMESPACE_STD +namespace datapar { + +template +inline constexpr bool __is_vectorizable_type_v = __is_standard_integer_type_v<_Tp> || __is_character_type_v<_Tp>; + +template <> +inline constexpr bool __is_vectorizable_type_v = true; + +template <> +inline constexpr bool __is_vectorizable_type_v = true; + +template +concept __value_preserving_convertible = requires(_From __from) { _To{__from}; }; + +template +concept __constexpr_wrapper_like = + convertible_to<_Tp, decltype(_Tp::value)> && equality_comparable_with<_Tp, decltype(_Tp::value)> && + bool_constant<_Tp() == _Tp::value>::value && + bool_constant(_Tp()) == _Tp::value>::value; + +// [simd.expos] +using __simd_size_type = int; + +template +struct __deduce_abi; + +template + requires __is_vectorizable_type_v<_Tp> && (_Np <= 64) +using __deduce_abi_t = __deduce_abi<_Tp>::template __apply<_Np>; + +template +using __native_abi = __deduce_abi<_Tp>::template __apply<4>; + +template +inline constexpr __simd_size_type __simd_size_v = 0; + +template +struct __integer_from_impl; + +template <> +struct __integer_from_impl<1> { + using type = uint8_t; +}; + +template <> +struct __integer_from_impl<2> { + using type = uint16_t; +}; + +template <> +struct __integer_from_impl<4> { + using type = uint32_t; +}; + +template <> +struct __integer_from_impl<8> { + using type = uint64_t; +}; + +template +using __integer_from = __integer_from_impl<_Bytes>::type; + +// ABI Types + +template +struct __vector_size_abi { + using _SimdT [[__gnu__::__vector_size__(_Np * sizeof(_Tp))]] = _Tp; + using _MaskT [[__gnu__::__vector_size__(_Np * sizeof(_Tp))]] = __integer_from; + + _LIBCPP_ALWAYS_INLINE constexpr _SimdT __select(_MaskT __mask, _SimdT __true, _SimdT __false) { + return __mask ? __true : __false; + } + +# ifdef _LIBCPP_COMPILER_CLANG_BASED + using _BoolVec __attribute__((__ext_vector_type__(_Np))) = bool; + + static constexpr auto __int_size = _Np <= 8 ? 8 : _Np <= 16 ? 16 : _Np <= 32 ? 32 : 64; + static_assert(__int_size >= _Np); + + using _IntSizeBoolVec __attribute__((__ext_vector_type__(__int_size))) = bool; + + _LIBCPP_ALWAYS_INLINE static constexpr auto __mask_to_int(_BoolVec __mask) noexcept { + return [&](index_sequence<_Origs...>, index_sequence<_Fillers...>) + _LIBCPP_ALWAYS_INLINE { + auto __vec = __builtin_convertvector( + __builtin_shufflevector(__mask, _BoolVec{}, _Origs..., ((void)_Fillers, _Np)...), _IntSizeBoolVec); + if constexpr (_Np <= 8) + return __builtin_bit_cast(unsigned char, __vec); + else if constexpr (_Np <= 16) + return __builtin_bit_cast(unsigned short, __vec); + else if constexpr (_Np <= 32) + return __builtin_bit_cast(unsigned int, __vec); + else + return __builtin_bit_cast(unsigned long long, __vec); + }(make_index_sequence<_Np>{}, make_index_sequence<__int_size - _Np>{}); + } + + _LIBCPP_ALWAYS_INLINE static constexpr bool __any_of(_MaskT __mask) noexcept { + return __builtin_reduce_or(__builtin_convertvector(__mask, _BoolVec)); + } + + _LIBCPP_ALWAYS_INLINE static constexpr bool __all_of(_MaskT __mask) noexcept { + return __builtin_reduce_and(__builtin_convertvector(__mask, _BoolVec)); + } + + _LIBCPP_ALWAYS_INLINE static constexpr __simd_size_type __reduce_count(_MaskT __mask) noexcept { + return __builtin_reduce_add(__builtin_convertvector(__builtin_convertvector(__mask, _BoolVec), _MaskT)); + } + + _LIBCPP_ALWAYS_INLINE static constexpr __simd_size_type __reduce_min_index(_MaskT __mask) noexcept { + return __builtin_ctzg(__mask_to_int(__builtin_convertvector(__mask, _BoolVec))); + } + + _LIBCPP_ALWAYS_INLINE static constexpr __simd_size_type __reduce_max_index(_MaskT __mask) noexcept { + return __int_size - 1 - __builtin_clzg(__mask_to_int(__builtin_convertvector(__mask, _BoolVec))); + } +# else + _LIBCPP_ALWAYS_INLINE constexpr bool __any_of(_MaskT __mask) noexcept { + for (size_t __i = 0; __i != _Np; ++__i) { + if (__mask[__i]) + return true; + } + return false; + } +# endif +}; + +template + requires __is_vectorizable_type_v<_Tp> +struct __deduce_abi<_Tp> { + template <__simd_size_type _Np> + using __apply = __vector_size_abi<_Tp, _Np>; +}; + +template +inline constexpr __simd_size_type __simd_size_v<_Tp, __vector_size_abi<_Tp, _Np>> = _Np; + +} // namespace datapar +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 26 + +#endif // _LIBCPP___SIMD_ABI_H diff --git a/libcxx/include/__simd/basic_simd.h b/libcxx/include/__simd/basic_simd.h new file mode 100644 index 0000000000000..acffa012d9ba1 --- /dev/null +++ b/libcxx/include/__simd/basic_simd.h @@ -0,0 +1,350 @@ +//===----------------------------------------------------------------------===// +// +// 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___SIMD_BASIC_SIMD_H +#define _LIBCPP___SIMD_BASIC_SIMD_H + +#include <__assert> +#include <__concepts/convertible_to.h> +#include <__config> +#include <__memory/assume_aligned.h> +#include <__ranges/concepts.h> +#include <__simd/abi.h> +#include <__simd/basic_simd_mask.h> +#include <__simd/simd_flags.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/pack_utils.h> +#include <__type_traits/remove_const.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/integer_sequence.h> + +#if _LIBCPP_STD_VER >= 26 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace datapar { + +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi") +template > +class basic_simd { +public: + using value_type = _Tp; + using mask_type = basic_simd_mask; + using abi_type = _Abi; + +private: + using __data_t = abi_type::_SimdT; + + __data_t __data_; + + _LIBCPP_ALWAYS_INLINE static constexpr __data_t __broadcast(value_type __value) { + return [&](index_sequence<_Indices...>) _LIBCPP_ALWAYS_INLINE noexcept { + return __data_t{((void)_Indices, __value)...}; + }(make_index_sequence{}); + } + + template + _LIBCPP_ALWAYS_INLINE static constexpr __data_t __load_from_pointer(const _Up* __ptr) { + return [&](index_sequence<_Indices...>) _LIBCPP_ALWAYS_INLINE noexcept { + return __data_t{__ptr[_Indices]...}; + }(make_index_sequence{}); + } + +public: + static constexpr integral_constant<__simd_size_type, __simd_size_v> size{}; + + constexpr basic_simd() noexcept = default; + + // [simd.ctor] + template _Up, class _From = remove_cvref_t<_Up>> + requires(__value_preserving_convertible<_From, value_type> || + (!is_arithmetic_v<_From> && !__constexpr_wrapper_like<_From>) || + (__constexpr_wrapper_like<_From> && is_arithmetic_v> && + bool_constant<(static_cast(_From::value) == _From::value)>::value)) + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd(_Up&& __value) noexcept : __data_{__broadcast(__value)} {} + + // TODO: converting constructor + // TODO: generator constructor + // TODO: flag constructor + // TODO: mask flag constructortrue + + template + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd(_Range&& __range, simd_flags<_Flags...> = {}) noexcept + requires(ranges::size(__range) == size()) + { + static_assert(__is_vectorizable_type_v>, "Range has to be of a vectorizable type"); + static_assert(__contains_type_v<__type_list<_Flags...>, __convert_flag> || + __value_preserving_convertible, value_type>, + "implicit conversion is not value preserving - consider using std::datapar::simd_flag_convert"); + auto* __ptr = std::assume_aligned<__get_align_for>(std::to_address(ranges::begin(__range))); + __data_ = __load_from_pointer(__ptr); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd( + _Range&& __range, const mask_type& __mask, simd_flags<_Flags...> = {}) noexcept + requires(ranges::size(__range) == size()) + { + static_assert(__is_vectorizable_type_v>, "Range has to be of a vectorizable type"); + static_assert(__contains_type_v<__type_list<_Flags...>, __convert_flag> || + __value_preserving_convertible, value_type>, + "implicit conversion is not value preserving - consider using std::datapar::simd_flag_convert"); + auto* __ptr = std::assume_aligned<__get_align_for>(std::to_address(ranges::begin(__range))); + __data_ = abi_type::__select(__mask.__data_, __load_from_pointer(__ptr), __broadcast(0)); + } + + // libc++ extensions + _LIBCPP_ALWAYS_INLINE constexpr explicit basic_simd(__data_t __data) noexcept : __data_(__data) {} + + // [simd.subscr] + _LIBCPP_HIDE_FROM_ABI constexpr value_type operator[](__simd_size_type __index) const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__index >= 0 && __index < size(), "simd::operator[] out of bounds"); + return __data_[__index]; + } + + // [simd.unary] + + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd& operator++() noexcept + requires requires(value_type __v) { ++__v; } + { + __data_ += 1; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator++(int) noexcept + requires requires(value_type __v) { __v++; } + { + auto __ret = *this; + ++*this; + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd& operator--() noexcept + requires requires(value_type __v) { --__v; } + { + __data_ -= 1; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator--(int) noexcept + requires requires(value_type __v) { __v--; } + { + auto __ret = *this; + --*this; + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI constexpr mask_type operator!() const noexcept + requires requires(value_type __v) { !__v; } + { + return mask_type(!__data_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator~() const noexcept + requires requires(value_type __v) { ~__v; } + { + return basic_simd(~__data_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator+() const noexcept + requires requires(value_type __v) { +__v; } + { + return basic_simd(+__data_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_simd operator-() const noexcept + requires requires(value_type __v) { -__v; } + { + return basic_simd(-__data_); + } + + // [simd.binary] + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator+(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v + __v; } + { + return basic_simd(__lhs.__data_ + __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator-(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v - __v; } + { + return basic_simd(__lhs.__data_ - __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator*(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v * __v; } + { + return basic_simd(__lhs.__data_ * __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator/(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v / __v; } + { + return basic_simd(__lhs.__data_ / __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator%(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v % __v; } + { + return basic_simd(__lhs.__data_ % __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator&(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v & __v; } + { + return basic_simd(__lhs.__data_ & __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator|(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v | __v; } + { + return basic_simd(__lhs.__data_ | __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd operator^(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v ^ __v; } + { + return basic_simd(__lhs.__data_ ^ __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd + operator<<(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v << __v; } + { + return basic_simd(__lhs.__data_ << __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd + operator>>(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v << __v; } + { + return basic_simd(__lhs.__data_ >> __rhs.__data_); + } + + // [simd.cassign] + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator+=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v += __v; } + { + __lhs.__data_ = __lhs.__data_ + __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator-=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v -= __v; } + { + __lhs.__data_ = __lhs.__data_ - __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator*=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v *= __v; } + { + __lhs.__data_ = __lhs.__data_ * __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator/=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v /= __v; } + { + __lhs.__data_ = __lhs.__data_ / __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator%=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v %= __v; } + { + __lhs.__data_ = __lhs.__data_ % __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator&=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v &= __v; } + { + __lhs.__data_ = __lhs.__data_ & __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator|=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v |= __v; } + { + __lhs.__data_ = __lhs.__data_ | __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator^=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v ^= __v; } + { + __lhs.__data_ = __lhs.__data_ ^ __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator<<=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v <<= __v; } + { + __lhs.__data_ = __lhs.__data_ << __rhs.__data_; + return __lhs; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr basic_simd& operator>>=(basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v >>= __v; } + { + __lhs.__data_ = __lhs.__data_ >> __rhs.__data_; + return __lhs; + } + + // [simd.comparisons] + _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator==(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v == __v; } + { + return mask_type(__lhs.__data_ == __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator!=(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v != __v; } + { + return mask_type(!(__lhs.__data_ == __rhs.__data_)); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator<(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v < __v; } + { + return mask_type(__lhs.__data_ < __rhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator>=(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v >= __v; } + { + return mask_type(__rhs.__data_ <= __lhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator>(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v > __v; } + { + return mask_type(__rhs.__data_ < __lhs.__data_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr mask_type operator<=(const basic_simd& __lhs, const basic_simd& __rhs) noexcept + requires requires(value_type __v) { __v <= __v; } + { + return mask_type(__lhs.__data_ <= __rhs.__data_); + } +}; +_LIBCPP_DIAGNOSTIC_POP + +template >> +using simd = basic_simd<_Tp, __deduce_abi_t<_Tp, _Np>>; + +} // namespace datapar +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 26 + +#endif // _LIBCPP___SIMD_BASIC_SIMD_H diff --git a/libcxx/include/__simd/basic_simd_mask.h b/libcxx/include/__simd/basic_simd_mask.h new file mode 100644 index 0000000000000..b2f93d1c9705b --- /dev/null +++ b/libcxx/include/__simd/basic_simd_mask.h @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// 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___SIMD_BASIC_SIMD_MASK_H +#define _LIBCPP___SIMD_BASIC_SIMD_MASK_H + +#include <__assert> +#include <__config> +#include <__cstddef/size_t.h> +#include <__simd/abi.h> +#include <__utility/integer_sequence.h> + +#if _LIBCPP_STD_VER >= 26 + +_LIBCPP_BEGIN_NAMESPACE_STD +namespace datapar { + +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi") + +struct __from_data_tag {}; +inline constexpr __from_data_tag __from_data; + +template >> +class basic_simd_mask { +public: + using value_type = bool; + using abi_type = _Abi; + + static constexpr integral_constant<__simd_size_type, __simd_size_v<__integer_from<_Bytes>, abi_type>> size{}; + +private: + using __data_t = abi_type::_MaskT; + __data_t __data_; + + _LIBCPP_ALWAYS_INLINE static constexpr __data_t __broadcast(value_type __value) { + return [&](index_sequence<_Indices...>) _LIBCPP_ALWAYS_INLINE { + return __data_t{((void)_Indices, __value)...}; + }(make_index_sequence{}); + } + +public: + // [simd.mask.ctor] + _LIBCPP_HIDE_FROM_ABI constexpr explicit basic_simd_mask(value_type __value) noexcept + : __data_(__broadcast(__value)) {} + + // TODO: converting constructor + + // TODO: generating constructor + + // libc++ extension + _LIBCPP_ALWAYS_INLINE constexpr explicit basic_simd_mask(__data_t __data) noexcept : __data_(__data) {} + _LIBCPP_ALWAYS_INLINE constexpr explicit operator __data_t() noexcept { return __data_; } + + // [simd.mask.subscr] + _LIBCPP_HIDE_FROM_ABI constexpr value_type operator[](__simd_size_type __i) const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i >= 0 && __i < size(), "simd_mask::operator[] out of bounds"); + return __data_[__i]; + } + + // TODO: [simd.mask.unary] + + // TODO: [simd.mask.conv] + + // TODO: [simd.mask.binary] + + // TODO: [simd.mask.cassign] + + // TODO: [simd.mask.comparison] + + // TODO: [simd.mask.cond] + + template + friend constexpr bool none_of(const basic_simd_mask<_Bytes2, _Abi2>&) noexcept; + + template + friend constexpr bool any_of(const basic_simd_mask<_Bytes2, _Abi2>&) noexcept; + + template + friend constexpr bool all_of(const basic_simd_mask<_Bytes2, _Abi2>&) noexcept; + + template + friend constexpr __simd_size_type reduce_count(const basic_simd_mask<_Bytes2, _Abi2>&) noexcept; + + template + friend constexpr __simd_size_type reduce_min_index(const basic_simd_mask<_Bytes2, _Abi2>&) noexcept; + + template + friend constexpr __simd_size_type reduce_max_index(const basic_simd_mask<_Bytes2, _Abi2>&) noexcept; +}; + +template >> +using simd_mask = basic_simd_mask>; + +// [simd.mask.reductions] + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool none_of(const basic_simd_mask<_Bytes, _Abi>& __mask) noexcept { + return !_Abi::__any_of(__mask.__data_); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool any_of(const basic_simd_mask<_Bytes, _Abi>& __mask) noexcept { + return _Abi::__any_of(__mask.__data_); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool all_of(const basic_simd_mask<_Bytes, _Abi>& __mask) noexcept { + return _Abi::__all_of(__mask.__data_); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr __simd_size_type reduce_count(const basic_simd_mask<_Bytes, _Abi>& __mask) noexcept { + return _Abi::__reduce_count(__mask.__data_); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr __simd_size_type +reduce_min_index(const basic_simd_mask<_Bytes, _Abi>& __mask) noexcept { + return _Abi::__reduce_min_index(__mask.__data_); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr __simd_size_type +reduce_max_index(const basic_simd_mask<_Bytes, _Abi>& __mask) noexcept { + return _Abi::__reduce_max_index(__mask.__data_); +} + +_LIBCPP_DIAGNOSTIC_POP + +} // namespace datapar +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 26 + +#endif // _LIBCPP___SIMD_BASIC_SIMD_MASK_H diff --git a/libcxx/include/__simd/simd_flags.h b/libcxx/include/__simd/simd_flags.h new file mode 100644 index 0000000000000..2184c4c41836d --- /dev/null +++ b/libcxx/include/__simd/simd_flags.h @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// 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___SIMD_SIMD_FLAGS_H +#define _LIBCPP___SIMD_SIMD_FLAGS_H + +#include <__algorithm/max.h> +#include <__bit/has_single_bit.h> +#include <__config> +#include <__cstddef/size_t.h> +#include <__type_traits/pack_utils.h> + +#if _LIBCPP_STD_VER >= 26 + +_LIBCPP_BEGIN_NAMESPACE_STD +namespace datapar { + +template +inline constexpr bool __is_flag_v = false; + +struct __aligned_flag {}; + +template <> +inline constexpr bool __is_flag_v<__aligned_flag> = true; + +struct __convert_flag {}; + +template <> +inline constexpr bool __is_flag_v<__convert_flag> = true; + +template +struct __overaligned_flag {}; + +template +inline constexpr bool __is_flag_v<__overaligned_flag<_Np>> = true; + +template +inline constexpr size_t __get_max_overaligned = 0; + +template +inline constexpr size_t __get_max_overaligned<__overaligned_flag<_Np>, _Args...> = + std::max(_Np, __get_max_overaligned<_Args...>); + +template +inline constexpr size_t __get_max_overaligned<_Tp, _Args...> = __get_max_overaligned<_Args...>; + +// TODO: Also add alignment when __aligned_flag is in _Args +template +inline constexpr size_t __get_align_for = std::max(1uz, __get_max_overaligned<_Args...>); + +template + requires(__is_flag_v<_Flags> && ...) +struct simd_flags { + template + static consteval auto __copy_aligned(simd_flags<_Args...>, simd_flags<_Result...>) { + if constexpr (__contains_type_v<__type_list<_Args...>, __aligned_flag>) { + return simd_flags<__aligned_flag, _Result...>{}; + } else { + return simd_flags<_Result...>{}; + } + } + + template + static consteval auto __copy_convert(simd_flags<_Args...>, simd_flags<_Result...>) { + if constexpr (__contains_type_v<__type_list<_Args...>, __convert_flag>) { + return simd_flags<__convert_flag, _Result...>{}; + } else { + return simd_flags<_Result...>{}; + } + } + + template + static consteval auto __copy_overaligned(simd_flags<_Args...>, simd_flags<_Result...>) { + if constexpr (constexpr auto __max_align = __get_max_overaligned<_Args...>; __max_align > 0) { + return simd_flags<__overaligned_flag<__max_align>, _Result...>{}; + } else { + return simd_flags<_Result...>{}; + } + } + + template + friend consteval auto operator|(simd_flags, simd_flags<_Other...>) { + using _Combined = simd_flags<_Flags..., _Other...>; + return __copy_overaligned(_Combined{}, __copy_convert(_Combined{}, __copy_aligned(_Combined{}, {}))); + } +}; + +inline constexpr simd_flags<> simd_flag_default{}; +inline constexpr simd_flags<__convert_flag> simd_flag_convert{}; +inline constexpr simd_flags<__aligned_flag> simd_flag_aligned{}; + +template + requires(std::has_single_bit(_Np)) +inline constexpr simd_flags<__overaligned_flag<_Np>> simd_flag_overaligned{}; + +} // namespace datapar +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 26 + +#endif // _LIBCPP___SIMD_SIMD_FLAGS_H diff --git a/libcxx/include/__type_traits/pack_utils.h b/libcxx/include/__type_traits/pack_utils.h new file mode 100644 index 0000000000000..8bfd28a13ddfe --- /dev/null +++ b/libcxx/include/__type_traits/pack_utils.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// 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___TYPE_TRAITS_PACK_UTILS_H +#define _LIBCPP___TYPE_TRAITS_PACK_UTILS_H + +#include <__config> +#include <__type_traits/integral_constant.h> +#include <__type_traits/type_list.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline const bool __contains_type_v = [] -> bool { static_assert(false); }(); + +template +inline const bool __contains_type_v<__type_list<_Args...>, _SearchT> = (__is_same(_Args, _SearchT) || ...); + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_PACK_UTILS_H diff --git a/libcxx/include/__type_traits/standard_types.h b/libcxx/include/__type_traits/standard_types.h new file mode 100644 index 0000000000000..f94599259cbf4 --- /dev/null +++ b/libcxx/include/__type_traits/standard_types.h @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// 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___TYPE_TRAITS_STANDARD_TYPES_H +#define _LIBCPP___TYPE_TRAITS_STANDARD_TYPES_H + +#include <__config> +#include <__type_traits/integral_constant.h> +#include <__type_traits/remove_cv.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 26 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline constexpr bool __is_standard_signed_integer_type_v = false; + +template <> +inline constexpr bool __is_standard_signed_integer_type_v = true; + +template <> +inline constexpr bool __is_standard_signed_integer_type_v = true; + +template <> +inline constexpr bool __is_standard_signed_integer_type_v = true; + +template <> +inline constexpr bool __is_standard_signed_integer_type_v = true; + +template <> +inline constexpr bool __is_standard_signed_integer_type_v = true; + +template +inline constexpr bool __is_standard_unsigned_integer_type_v = false; + +template <> +inline constexpr bool __is_standard_unsigned_integer_type_v = true; + +template <> +inline constexpr bool __is_standard_unsigned_integer_type_v = true; + +template <> +inline constexpr bool __is_standard_unsigned_integer_type_v = true; + +template <> +inline constexpr bool __is_standard_unsigned_integer_type_v = true; + +template <> +inline constexpr bool __is_standard_unsigned_integer_type_v = true; + +template +inline constexpr bool __is_standard_integer_type_v = + __is_standard_signed_integer_type_v<_Tp> || __is_standard_unsigned_integer_type_v<_Tp>; + +template +inline constexpr bool __is_character_type_v = false; + +template <> +inline constexpr bool __is_character_type_v = true; + +template <> +inline constexpr bool __is_character_type_v = true; + +#if _LIBCPP_HAS_CHAR8_T +template <> +inline constexpr bool __is_character_type_v = true; +#endif + +template <> +inline constexpr bool __is_character_type_v = true; + +template <> +inline constexpr bool __is_character_type_v = true; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 26 + +#endif // _LIBCPP___TYPE_TRAITS_STANDARD_TYPES_H diff --git a/libcxx/include/simd b/libcxx/include/simd new file mode 100644 index 0000000000000..7627c2ac199fb --- /dev/null +++ b/libcxx/include/simd @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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_SIMD +#define _LIBCPP_SIMD + +#include <__config> + +#if _LIBCPP_STD_VER >= 26 +# include <__simd/basic_simd.h> +# include <__simd/basic_simd_mask.h> +# include <__simd/simd_flags.h> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#endif // _LIBCPP_SIMD diff --git a/libcxx/test/libcxx/numerics/simd/implementation_defined_conversions.pass.cpp b/libcxx/test/libcxx/numerics/simd/implementation_defined_conversions.pass.cpp new file mode 100644 index 0000000000000..bcdcf747c50b9 --- /dev/null +++ b/libcxx/test/libcxx/numerics/simd/implementation_defined_conversions.pass.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../../std/numerics/simd/utils.h" + +namespace dp = std::datapar; + +template +constexpr void test() { + simd_utils::test_sizes([](std::integral_constant) { + using vec [[gnu::vector_size(N * sizeof(T))]] = T; + }); +} + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { test(); }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/aliases.compile.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/aliases.compile.pass.cpp new file mode 100644 index 0000000000000..3ef6f39f5ba30 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/aliases.compile.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include + +#include "type_algorithms.h" +#include "../utils.h" + +namespace dp = std::datapar; + +template +inline constexpr bool is_signed_integral_constant = false; + +template +inline constexpr bool is_signed_integral_constant> = std::is_signed_v; + +template +constexpr void test() { + { // check size deduction + using simd_t = dp::simd; + static_assert(std::is_same_v); + static_assert( + std::is_same_v>); + + static_assert(is_signed_integral_constant>); + } + + { // check a few explicit sizes + simd_utils::test_sizes([](std::integral_constant) { static_assert(dp::simd::size == N); }); + } +} + +static_assert([] { + types::for_each(types::vectorizable_types{}, [] { test(); }); + + return true; +}()); diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/add.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/add.pass.cpp new file mode 100644 index 0000000000000..9b65dd986803a --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/add.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + const dp::simd vec(arr); // make sure operator+ is const + std::same_as> auto&& ret = vec + vec; + for (int i = 0; i != N; ++i) + assert(ret[i] == T(2 * i)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitand.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitand.pass.cpp new file mode 100644 index 0000000000000..73fb97a12de3e --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitand.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_bitand = requires(T v) { v & v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + const dp::simd vec(arr); // make sure operator& is const + const dp::simd mask(T(15)); + std::same_as> auto&& ret = vec & mask; + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) % 16)); + }); + }); + + static_assert(has_bitand>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_bitand>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitor.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitor.pass.cpp new file mode 100644 index 0000000000000..e92e7643f12ec --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitor.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_bitor = requires(T v) { v | v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + const dp::simd vec(arr); // make sure operator& is const + const dp::simd mask(T(15)); + std::same_as> auto&& ret = vec | mask; + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) | 15)); + }); + }); + + static_assert(has_bitor>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_bitor>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitshift_left.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitshift_left.pass.cpp new file mode 100644 index 0000000000000..2236ebdccb829 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitshift_left.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_bitshift_left = requires(T v) { v << v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + const dp::simd vec(arr); // make sure operator<< is const + const dp::simd mask(T(3)); + std::same_as> auto&& ret = vec << mask; + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) << 3)); + }); + }); + + static_assert(has_bitshift_left>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_bitshift_left>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitshift_right.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitshift_right.pass.cpp new file mode 100644 index 0000000000000..cd09631bef463 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/bitshift_right.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_bitshift_right = requires(T v) { v >> v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + const dp::simd vec(arr); // make sure operator>> is const + const dp::simd mask(T(3)); + std::same_as> auto&& ret = vec >> mask; + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) >> 3)); + }); + }); + + static_assert(has_bitshift_right>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + static_assert(!has_bitshift_right>); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/divide.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/divide.pass.cpp new file mode 100644 index 0000000000000..533311f6a092b --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/divide.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 1); + const dp::simd vec(arr); // make sure operator/ is const + std::same_as> auto&& ret = vec / vec; + for (int i = 0; i != N; ++i) + assert(ret[i] == T(1)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/modulo.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/modulo.pass.cpp new file mode 100644 index 0000000000000..9315da95a1063 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/modulo.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_modulo = requires(T v) { v % v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 1); + const dp::simd vec(arr); // make sure operator- is const + std::same_as> auto&& ret = vec % vec; + for (int i = 0; i != N; ++i) + assert(ret[i] == T(0)); + }); + }); + + static_assert(has_modulo>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_modulo>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/multiply.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/multiply.pass.cpp new file mode 100644 index 0000000000000..c2f085b1f96c7 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/multiply.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + for (size_t i = 0; i != N; ++i) + arr[i] = i % 8; + const dp::simd vec(arr); // make sure operator* is const + std::same_as> auto&& ret = vec * vec; + for (int i = 0; i != N; ++i) { + auto mod = i % 8; + assert(ret[i] == T(mod * mod)); + } + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/subtract.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/subtract.pass.cpp new file mode 100644 index 0000000000000..d63fa1c96cfd6 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/subtract.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + const dp::simd vec(arr); // make sure operator- is const + std::same_as> auto&& ret = vec - vec; + for (int i = 0; i != N; ++i) + assert(ret[i] == T(0)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.binary/xor.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.binary/xor.pass.cpp new file mode 100644 index 0000000000000..02b7000e097f3 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.binary/xor.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_xor = requires(T v) { v ^ v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + const dp::simd vec(arr); // make sure operator& is const + const dp::simd mask(T(15)); + std::same_as> auto&& ret = vec ^ mask; + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) ^ 15)); + }); + }); + + static_assert(has_xor>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_xor>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/add.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/add.pass.cpp new file mode 100644 index 0000000000000..9e47965ec2923 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/add.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + dp::simd vec(arr); + const dp::simd vec2(T(3)); // make sure operator+ is const + std::same_as&> auto&& ret = vec += vec2; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T(i + 3)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitand.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitand.pass.cpp new file mode 100644 index 0000000000000..59f218d837d88 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitand.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_bitand = requires(T v) { v &= v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + dp::simd vec(arr); + const dp::simd mask(T(15)); // make sure operator& is const + std::same_as&> auto&& ret = vec &= mask; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) % 16)); + }); + }); + + static_assert(has_bitand>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_bitand>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitor.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitor.pass.cpp new file mode 100644 index 0000000000000..264474befa3c9 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitor.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_bitor = requires(T v) { v |= v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + dp::simd vec(arr); // make sure operator& is const + const dp::simd mask(T(15)); + std::same_as&> auto&& ret = vec |= mask; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) | 15)); + }); + }); + + static_assert(has_bitor>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_bitor>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitshift_left.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitshift_left.pass.cpp new file mode 100644 index 0000000000000..b254a8d2fcd73 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitshift_left.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_bitshift_left = requires(T v) { v <<= v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + dp::simd vec(arr); // make sure operator<< is const + const dp::simd mask(T(3)); + std::same_as&> auto&& ret = vec <<= mask; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) << 3)); + }); + }); + + static_assert(has_bitshift_left>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_bitshift_left>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitshift_right.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitshift_right.pass.cpp new file mode 100644 index 0000000000000..6ab087186c978 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/bitshift_right.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_bitshift_right = requires(T v) { v >>= v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + dp::simd vec(arr); // make sure operator>> is const + const dp::simd mask(T(3)); + std::same_as&> auto&& ret = vec >>= mask; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) >> 3)); + }); + }); + + static_assert(has_bitshift_right>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + static_assert(!has_bitshift_right>); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/divide.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/divide.pass.cpp new file mode 100644 index 0000000000000..24d18c67a3307 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/divide.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 55); + dp::simd vec(arr); + const dp::simd vec2(T(6)); // make sure operator- is const + std::same_as&> auto&& ret = vec /= vec2; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T(i + 55) / 6); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/modulo.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/modulo.pass.cpp new file mode 100644 index 0000000000000..cc19bd3f02aaa --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/modulo.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_modulo = requires(T v) { v %= v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + dp::simd vec(arr); + const dp::simd vec2(T(5)); // make sure operator% is const + std::same_as&> auto&& ret = vec %= vec2; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T(i % 5)); + }); + }); + + static_assert(has_modulo>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_modulo>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/multiply.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/multiply.pass.cpp new file mode 100644 index 0000000000000..fd574a5259be8 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/multiply.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + dp::simd vec(arr); + const dp::simd vec2(T(2)); // make sure operator- is const + std::same_as&> auto&& ret = vec *= vec2; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T(i * 2)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/subtract.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/subtract.pass.cpp new file mode 100644 index 0000000000000..7be41d0d578ba --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/subtract.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 5); + dp::simd vec(arr); + const dp::simd vec2(T(3)); // make sure operator- is const + std::same_as&> auto&& ret = vec -= vec2; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(ret[i] == T(i + 2)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.cassign/xor.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/xor.pass.cpp new file mode 100644 index 0000000000000..0f3ed21e45a88 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.cassign/xor.pass.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_xor = requires(T v) { v ^= v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 54); + dp::simd vec(arr); // make sure operator& is const + const dp::simd mask(T(15)); + std::same_as&> auto&& ret = vec ^= mask; + for (int i = 0; i != N; ++i) + assert(ret[i] == T((i + 54) ^ 15)); + }); + }); + + static_assert(has_xor>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_xor>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.comparison/equality.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.comparison/equality.pass.cpp new file mode 100644 index 0000000000000..7ec14111fed35 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.comparison/equality.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +constexpr void test(dp::simd lhs, dp::simd rhs, std::array expected) { + { // Test operator== + std::same_as::mask_type> auto result = lhs == rhs; + for (size_t i = 0; i != N; ++i) { + assert(result[i] == expected[i]); + } + } + { // Test operator!= + std::same_as::mask_type> auto result = lhs != rhs; + for (size_t i = 0; i != N; ++i) { + assert(result[i] == !expected[i]); + } + } +} + +template +constexpr void test() { + test(std::array{1, 2, 3, 4}, std::array{1, 2, 3, 4}, {true, true, true, true}); + test(std::array{4, 3, 2, 1}, std::array{1, 2, 3, 4}, {false, false, false, false}); + test(std::array{1, 2, 3, 4}, std::array{1, 2, 4, 3}, {true, true, false, false}); + test(std::array{1, 1, 3, 4}, std::array{1, 2, 4, 1}, {true, false, false, false}); +} + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { test(); }); + types::for_each(types::vectorizable_float_types{}, [] { + constexpr auto nan = std::numeric_limits::quiet_NaN(); + dp::simd a = std::array{nan, nan, nan, nan}; + dp::simd b = a; + assert(dp::none_of(a == b)); + assert(dp::all_of(a != b)); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.comparison/ordering.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.comparison/ordering.pass.cpp new file mode 100644 index 0000000000000..69b5bcd071f89 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.comparison/ordering.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +constexpr void test(dp::simd lhs, dp::simd rhs, std::array expected) { + { // Test operator< + std::same_as::mask_type> auto result = lhs < rhs; + for (size_t i = 0; i != N; ++i) { + assert(result[i] == expected[i]); + } + } + { // Test operator> + std::same_as::mask_type> auto result = rhs > lhs; + for (size_t i = 0; i != N; ++i) { + assert(result[i] == expected[i]); + } + } + { // Test operator>= + std::same_as::mask_type> auto result = lhs >= rhs; + for (size_t i = 0; i != N; ++i) { + assert(result[i] == !expected[i]); + } + } + { // Test operator<= + std::same_as::mask_type> auto result = rhs <= lhs; + for (size_t i = 0; i != N; ++i) { + assert(result[i] == !expected[i]); + } + } +} + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + test(std::array{1, 2, 3, 4}, std::array{1, 2, 3, 4}, {false, false, false, false}); + test(std::array{4, 3, 2, 1}, std::array{1, 2, 3, 4}, {false, false, true, true}); + test(std::array{1, 2, 3, 4}, std::array{1, 2, 4, 3}, {false, false, true, false}); + test(std::array{1, 1, 3, 4}, std::array{1, 2, 4, 1}, {false, true, true, false}); + }); + types::for_each(types::vectorizable_float_types{}, [] { + constexpr auto nan = std::numeric_limits::quiet_NaN(); + dp::simd a = std::array{nan, nan, nan, nan}; + dp::simd b = a; + assert(dp::none_of(a < b)); + assert(dp::none_of(a > b)); + assert(dp::none_of(a <= b)); + assert(dp::none_of(a >= b)); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.ctor/broadcast.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.ctor/broadcast.pass.cpp new file mode 100644 index 0000000000000..aa7d8e5e961e1 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.ctor/broadcast.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_broadcast_constructor = requires { dp::simd(std::declval()); }; + +static_assert(has_broadcast_constructor); +static_assert(has_broadcast_constructor); +static_assert(!has_broadcast_constructor); +static_assert(!has_broadcast_constructor); +static_assert(!has_broadcast_constructor); +static_assert(!has_broadcast_constructor); +static_assert(!has_broadcast_constructor); +static_assert(!has_broadcast_constructor); + +struct convertible_to_int { + operator int(); +}; + +static_assert(has_broadcast_constructor); +static_assert(has_broadcast_constructor); + +struct almost_constexpr_wrapper_like { + static constexpr int value = 34; + + constexpr int operator()() const { return value; } + operator int() const { return value; } + friend constexpr bool operator==(almost_constexpr_wrapper_like, almost_constexpr_wrapper_like) = default; + friend constexpr bool operator==(almost_constexpr_wrapper_like lhs, int rhs) { return lhs.value == rhs; } +}; +LIBCPP_STATIC_ASSERT(!dp::__constexpr_wrapper_like); + +static_assert(has_broadcast_constructor); +static_assert(has_broadcast_constructor); + +template +struct constexpr_wrapper_like { + static constexpr T value = Val; + + constexpr T operator()() const { return value; } + constexpr operator T() const { return value; } + friend constexpr bool operator==(constexpr_wrapper_like, constexpr_wrapper_like) = default; + friend constexpr bool operator==(constexpr_wrapper_like lhs, T rhs) { return lhs.value == rhs; } +}; +LIBCPP_STATIC_ASSERT(dp::__constexpr_wrapper_like>); + +static_assert(!has_broadcast_constructor>); +static_assert(!has_broadcast_constructor>); +static_assert(has_broadcast_constructor>); +static_assert(has_broadcast_constructor>); + +template +constexpr void test() { + simd_utils::test_sizes([](std::integral_constant) { + dp::simd vec(T(1)); + for (auto i = 0; i != vec.size(); ++i) + assert(vec[i] == T(1)); + }); +} + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { test(); }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.ctor/range.mask.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.ctor/range.mask.pass.cpp new file mode 100644 index 0000000000000..57b2c3197cb99 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.ctor/range.mask.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +constexpr void test() { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + dp::simd vec(arr); + for (auto i = 0; i != vec.size(); ++i) + assert(vec[i] == T(i)); + }); +} + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { test(); }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.ctor/range.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.ctor/range.pass.cpp new file mode 100644 index 0000000000000..57b2c3197cb99 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.ctor/range.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +constexpr void test() { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + dp::simd vec(arr); + for (auto i = 0; i != vec.size(); ++i) + assert(vec[i] == T(i)); + }); +} + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { test(); }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.unary/identity.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.unary/identity.pass.cpp new file mode 100644 index 0000000000000..639bfd30bfa8f --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.unary/identity.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + const dp::simd vec(arr); // make sure operator+ is const + std::same_as> auto&& ret = +vec; + assert(dp::all_of(ret == vec)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.unary/invert.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.unary/invert.pass.cpp new file mode 100644 index 0000000000000..73322ceae2a05 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.unary/invert.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +template +concept has_invert = requires(T v) { ~v; }; + +constexpr bool test() { + types::for_each(types::standard_integer_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + const dp::simd vec(arr); // make sure operator~ is const + std::same_as> auto&& ret = ~vec; + for (int i = 0; i != N; ++i) + assert(ret[i] == T(~i)); + }); + }); + + static_assert(has_invert>); + + types::for_each(types::vectorizable_float_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { static_assert(!has_invert>); }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.unary/negation.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.unary/negation.pass.cpp new file mode 100644 index 0000000000000..517eaea14d31a --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.unary/negation.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + const dp::simd vec(arr); // make sure operator- is const + std::same_as> auto&& ret = -vec; + for (int i = 0; i != N; ++i) + assert(ret[i] == T(-i)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.unary/not.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.unary/not.pass.cpp new file mode 100644 index 0000000000000..6ef61cd00e73c --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.unary/not.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + for (size_t i = 0; i != N; ++i) + arr[i] = i % 2 == 0 ? 1 : 0; + const dp::simd vec(arr); // make sure operator! is const + std::same_as> auto&& ret = !vec; + for (int i = 0; i != N; ++i) + assert(ret[i] == (i % 2 == 1)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.unary/postdec.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.unary/postdec.pass.cpp new file mode 100644 index 0000000000000..036a0dbd2bf70 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.unary/postdec.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 1); + dp::simd vec(arr); + std::same_as> auto&& ret = vec--; + for (int i = 0; i != N; ++i) { + assert(ret[i] == T(i + 1)); + assert(vec[i] == T(i)); + } + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.unary/postinc.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.unary/postinc.pass.cpp new file mode 100644 index 0000000000000..9fec3a6d9b59e --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.unary/postinc.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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + dp::simd vec(arr); + std::same_as> auto&& ret = vec++; + for (int i = 0; i != N; ++i) { + assert(ret[i] == T(i)); + assert(vec[i] == T(i + 1)); + } + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.unary/predec.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.unary/predec.pass.cpp new file mode 100644 index 0000000000000..fa1d1da96d2bd --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.unary/predec.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 1); + dp::simd vec(arr); + std::same_as&> auto&& ret = --vec; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(vec[i] == T(i)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/simd.unary/preinc.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/simd.unary/preinc.pass.cpp new file mode 100644 index 0000000000000..3fa324eed62d3 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/simd.unary/preinc.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + simd_utils::test_sizes([](std::integral_constant) { + std::array arr; + std::iota(std::begin(arr), std::end(arr), 0); + dp::simd vec(arr); + std::same_as&> auto&& ret = ++vec; + assert(&ret == &vec); + for (int i = 0; i != N; ++i) + assert(vec[i] == T(i + 1)); + }); + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/subscript.assert.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/subscript.assert.pass.cpp new file mode 100644 index 0000000000000..6c6e81277d8a5 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/subscript.assert.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// Test hardening assertions for std::datapar::simd. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// REQUIRES: std-at-least-c++26 + +#include + +#include "check_assertion.h" +#include "../utils.h" + +namespace dp = std::datapar; + +int main(int, char**) { + simd_utils::test_sizes([](std::integral_constant) { + dp::simd vec; + TEST_LIBCPP_ASSERT_FAILURE(vec[-1], "simd::operator[] out of bounds"); + TEST_LIBCPP_ASSERT_FAILURE(vec[N], "simd::operator[] out of bounds"); + TEST_LIBCPP_ASSERT_FAILURE(vec[N + 1], "simd::operator[] out of bounds"); + }); + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.class/traits.compile.pass.cpp b/libcxx/test/std/numerics/simd/simd.class/traits.compile.pass.cpp new file mode 100644 index 0000000000000..44100ff90eede --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.class/traits.compile.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +#include "type_algorithms.h" +#include "../utils.h" + +namespace dp = std::datapar; + +template +constexpr void test() { + { // check size deduction + using simd_t = dp::simd; + static_assert(std::is_trivially_default_constructible_v); + static_assert(std::is_trivially_copyable_v); + } + + { // check a few explicit sizes + simd_utils::test_sizes([](std::integral_constant) { + static_assert(std::is_trivially_default_constructible_v>); + static_assert(std::is_trivially_copyable_v>); + }); + } +} + +static_assert([] { + types::for_each(types::vectorizable_types{}, [] { test(); }); + + return true; +}()); diff --git a/libcxx/test/std/numerics/simd/simd.flags.compile.pass.cpp b/libcxx/test/std/numerics/simd/simd.flags.compile.pass.cpp new file mode 100644 index 0000000000000..097903cd4fff4 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.flags.compile.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +namespace dp = std::datapar; + +template +struct unwrap_flag; + +template +struct unwrap_flag> { + using type = T; +}; + +using aligned_flag_t = unwrap_flag>::type; +using convert_flag_t = unwrap_flag>::type; +template +using overaligned_flag_t = unwrap_flag)>>::type; + +static_assert(std::is_same_v, decltype(dp::simd_flags<>{} | dp::simd_flags<>{})>); + +template +constexpr bool contains_type_v = false; + +template +constexpr bool contains_type_v, T> = (std::is_same_v || ...); + +template +consteval bool test(dp::simd_flags lhs, dp::simd_flags rhs) { + return contains_type_v; +} + +static_assert(test(dp::simd_flags{}, dp::simd_flags{})); +static_assert(test(dp::simd_flags<>{}, dp::simd_flags{})); +static_assert(test(dp::simd_flags{}, dp::simd_flags<>{})); +static_assert(!test(dp::simd_flags{}, dp::simd_flags<>{})); +static_assert(test(dp::simd_flags{}, dp::simd_flags<>{})); +static_assert(test(dp::simd_flags<>{}, dp::simd_flags{})); +static_assert(test(dp::simd_flags{}, dp::simd_flags{})); +static_assert(test>(dp::simd_flags>{}, dp::simd_flags<>{})); +static_assert(test>(dp::simd_flags<>{}, dp::simd_flags>{})); +static_assert(test>(dp::simd_flags>{}, dp::simd_flags>{})); +static_assert(test>(dp::simd_flags>{}, dp::simd_flags>{})); diff --git a/libcxx/test/std/numerics/simd/simd.mask.class/simd.mask.ctor/broadcast.pass.cpp b/libcxx/test/std/numerics/simd/simd.mask.class/simd.mask.ctor/broadcast.pass.cpp new file mode 100644 index 0000000000000..779cbf9fa215a --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.mask.class/simd.mask.ctor/broadcast.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include + +#include "type_algorithms.h" +#include "../../utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, []() { + { + dp::simd_mask vec(true); + for (auto i = 0; i != vec.size(); ++i) + assert(vec[i]); + } + { + dp::simd_mask vec(false); + for (auto i = 0; i != vec.size(); ++i) + assert(!vec[i]); + } + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.mask.class/subscript.assert.pass.cpp b/libcxx/test/std/numerics/simd/simd.mask.class/subscript.assert.pass.cpp new file mode 100644 index 0000000000000..2b5f5a5bb80e4 --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.mask.class/subscript.assert.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// Test hardening assertions for std::datapar::simd. + +// REQUIRES: has-unix-headers +// UNSUPPORTED: libcpp-hardening-mode=none +// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing + +// REQUIRES: std-at-least-c++26 + +#include + +#include "check_assertion.h" +#include "../utils.h" + +namespace dp = std::datapar; + +int main(int, char**) { + simd_utils::test_sizes([](std::integral_constant) { + dp::simd_mask vec(false); + TEST_LIBCPP_ASSERT_FAILURE(vec[-1], "simd::operator[] out of bounds"); + TEST_LIBCPP_ASSERT_FAILURE(vec[N], "simd::operator[] out of bounds"); + TEST_LIBCPP_ASSERT_FAILURE(vec[N + 1], "simd::operator[] out of bounds"); + }); + return 0; +} diff --git a/libcxx/test/std/numerics/simd/simd.mask.class/traits.compile.pass.cpp b/libcxx/test/std/numerics/simd/simd.mask.class/traits.compile.pass.cpp new file mode 100644 index 0000000000000..8a0de3dfe675f --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.mask.class/traits.compile.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +#include "type_algorithms.h" +#include "../utils.h" + +namespace dp = std::datapar; + +template +constexpr void test() { + { // check size deduction + using simd_t = dp::simd_mask; + static_assert(std::is_trivially_copyable_v); + } + + { // check a few explicit sizes + simd_utils::test_sizes([](std::integral_constant) { + static_assert(std::is_trivially_copyable_v>); + }); + } +} + +static_assert([] { + types::for_each(types::vectorizable_types{}, [] { test(); }); + + return true; +}()); diff --git a/libcxx/test/std/numerics/simd/simd.mask.reductions.pass.cpp b/libcxx/test/std/numerics/simd/simd.mask.reductions.pass.cpp new file mode 100644 index 0000000000000..8d3156acd42df --- /dev/null +++ b/libcxx/test/std/numerics/simd/simd.mask.reductions.pass.cpp @@ -0,0 +1,248 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// REQUIRES: std-at-least-c++26 + +#include +#include +#include + +#include "type_algorithms.h" +#include "utils.h" + +namespace dp = std::datapar; + +constexpr bool test() { + types::for_each(types::vectorizable_types{}, [] { + { // test with 4 elements (and non-trivial patterns) + { // simple check + auto mask = simd_utils::make_mask<4>({true, true, false, false}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 2); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 1); + } + { // all are true + auto mask = simd_utils::make_mask<4>({true, true, true, true}); + assert(dp::any_of(mask)); + assert(dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 4); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 3); + } + { // none are true + auto mask = simd_utils::make_mask<4>({false, false, false, false}); + assert(!dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(dp::none_of(mask)); + assert(dp::reduce_count(mask) == 0); + // no reduce_{min,max}_index, since the precondition isn't met. + } + { // interleaved true and false + auto mask = simd_utils::make_mask<4>({false, true, false, true}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 2); + assert(dp::reduce_min_index(mask) == 1); + assert(dp::reduce_max_index(mask) == 3); + } + { // single element is true at the start + auto mask = simd_utils::make_mask<4>({true, false, false, false}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 1); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 0); + } + { // single element is true in the middle + auto mask = simd_utils::make_mask<4>({false, true, false, false}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 1); + assert(dp::reduce_min_index(mask) == 1); + assert(dp::reduce_max_index(mask) == 1); + } + { // single element is true at the end + auto mask = simd_utils::make_mask<4>({false, false, false, true}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 1); + assert(dp::reduce_min_index(mask) == 3); + assert(dp::reduce_max_index(mask) == 3); + } + } + { // test with eight elements + { // simple check + auto mask = simd_utils::make_mask<8>({true, true, false, false, true, true, false, false}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 4); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 5); + } + { // all are true + auto mask = simd_utils::make_mask<8>({true, true, true, true, true, true, true, true}); + assert(dp::any_of(mask)); + assert(dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 8); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 7); + } + { // none are true + auto mask = simd_utils::make_mask<8>({false, false, false, false, false, false, false, false}); + assert(!dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(dp::none_of(mask)); + assert(dp::reduce_count(mask) == 0); + // no reduce_{min,max}_index, since the precondition isn't met. + } + } + { // test with sixteen elements + { // simple check + auto mask = simd_utils::make_mask<16>( + {true, true, false, false, true, true, false, false, true, true, false, false, true, true, false, false}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 8); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 13); + } + { // all are true + auto mask = simd_utils::make_mask<16>( + {true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true}); + assert(dp::any_of(mask)); + assert(dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 16); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 15); + } + { // none are true + auto mask = simd_utils::make_mask<16>( + {false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false}); + assert(!dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(dp::none_of(mask)); + assert(dp::reduce_count(mask) == 0); + // no reduce_{min,max}_index, since the precondition isn't met. + } + } + { // test with thirtytwo elements + { // simple check + auto mask = simd_utils::make_mask<32>( + {true, true, false, false, true, true, false, false, true, true, false, false, true, true, false, false, + true, true, false, false, true, true, false, false, true, true, false, false, true, true, false, false}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 16); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 29); + } + { // all are true + auto mask = simd_utils::make_mask<32>( + {true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true}); + assert(dp::any_of(mask)); + assert(dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 32); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 31); + } + { // none are true + auto mask = simd_utils::make_mask<32>( + {false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false}); + assert(!dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(dp::none_of(mask)); + assert(dp::reduce_count(mask) == 0); + // no reduce_{min,max}_index, since the precondition isn't met. + } + } + { // test with sixtyfour elements + { // simple check + auto mask = simd_utils::make_mask<64>( + {true, true, false, false, true, true, false, false, true, true, false, false, true, true, false, false, + true, true, false, false, true, true, false, false, true, true, false, false, true, true, false, false, + true, true, false, false, true, true, false, false, true, true, false, false, true, true, false, false, + true, true, false, false, true, true, false, false, true, true, false, false, true, true, false, false}); + assert(dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 32); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 61); + } + { // all are true + auto mask = simd_utils::make_mask<64>( + {true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true}); + assert(dp::any_of(mask)); + assert(dp::all_of(mask)); + assert(!dp::none_of(mask)); + assert(dp::reduce_count(mask) == 64); + assert(dp::reduce_min_index(mask) == 0); + assert(dp::reduce_max_index(mask) == 63); + } + { // none are true + auto mask = simd_utils::make_mask<64>( + {false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false}); + assert(!dp::any_of(mask)); + assert(!dp::all_of(mask)); + assert(dp::none_of(mask)); + assert(dp::reduce_count(mask) == 0); + // no reduce_{min,max}_index, since the precondition isn't met. + } + } + }); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/numerics/simd/utils.h b/libcxx/test/std/numerics/simd/utils.h new file mode 100644 index 0000000000000..57c2f846b5b5a --- /dev/null +++ b/libcxx/test/std/numerics/simd/utils.h @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// 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 TEST_STD_NUMERICS_SIMD_UTILS_H +#define TEST_STD_NUMERICS_SIMD_UTILS_H + +#include +#include +#include + +#include "type_algorithms.h" + +namespace types { +using vectorizable_float_types = type_list; +using vectorizable_types = types::concatenate_t; +} // namespace types + +namespace simd_utils { +template +constexpr void test_sizes(Func f) { + f(std::integral_constant{}); + f(std::integral_constant{}); + f(std::integral_constant{}); + f(std::integral_constant{}); + f(std::integral_constant{}); + f(std::integral_constant{}); + f(std::integral_constant{}); + f(std::integral_constant{}); + f(std::integral_constant{}); + f(std::integral_constant{}); +} + +template +constexpr std::datapar::simd_mask make_mask(std::array bools) { + std::array bools_as_int; + for (size_t i = 0; i != N; ++i) + bools_as_int[i] = bools[i] ? 1 : 0; + return std::datapar::simd(1) == std::datapar::simd(bools_as_int); +} +} // namespace simd_utils + +#endif // TEST_STD_NUMERICS_SIMD_UTILS_H diff --git a/libcxx/test/support/type_algorithms.h b/libcxx/test/support/type_algorithms.h index da3d0add4d0c4..291a26dc47bf9 100644 --- a/libcxx/test/support/type_algorithms.h +++ b/libcxx/test/support/type_algorithms.h @@ -99,29 +99,28 @@ using character_types = #endif >; +using standard_signed_integer_types = type_list; + +using standard_unsigned_integer_types = + type_list; + +using standard_integer_types = concatenate_t; + using signed_integer_types = - type_list #endif - >; + >; using unsigned_integer_types = - type_list #endif - >; + >; using integer_types = concatenate_t;