diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -907,6 +907,8 @@ experimental/__simd/abi_tag.h experimental/__simd/aligned_tag.h experimental/__simd/declaration.h + experimental/__simd/internal_declaration.h + experimental/__simd/reference.h experimental/__simd/scalar.h experimental/__simd/simd.h experimental/__simd/simd_mask.h diff --git a/libcxx/include/experimental/__simd/scalar.h b/libcxx/include/experimental/__simd/internal_declaration.h copy from libcxx/include/experimental/__simd/scalar.h copy to libcxx/include/experimental/__simd/internal_declaration.h --- a/libcxx/include/experimental/__simd/scalar.h +++ b/libcxx/include/experimental/__simd/internal_declaration.h @@ -7,23 +7,28 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP_EXPERIMENTAL___SIMD_SCALAR_H -#define _LIBCPP_EXPERIMENTAL___SIMD_SCALAR_H - -#include +#ifndef _LIBCPP_EXPERIMENTAL___SIMD_INTERNAL_DECLARATION_H +#define _LIBCPP_EXPERIMENTAL___SIMD_INTERNAL_DECLARATION_H #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL inline namespace parallelism_v2 { -namespace simd_abi { -struct __scalar { - static constexpr size_t __simd_size = 1; -}; -} // namespace simd_abi +template +struct __simd_storage; + +template +struct __mask_storage; + +template +struct __simd_operations; + +template +struct __mask_operations; + } // namespace parallelism_v2 _LIBCPP_END_NAMESPACE_EXPERIMENTAL #endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) -#endif // _LIBCPP_EXPERIMENTAL___SIMD_SCALAR_H +#endif // _LIBCPP_EXPERIMENTAL___SIMD_INTERNAL_DECLARATION_H diff --git a/libcxx/include/experimental/__simd/reference.h b/libcxx/include/experimental/__simd/reference.h new file mode 100644 --- /dev/null +++ b/libcxx/include/experimental/__simd/reference.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H +#define _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H + +#include + +#if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) + +_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL +inline namespace parallelism_v2 { +template +class __reference { // exposition only + template + friend class simd; + template + friend class simd_mask; + + _Storage& __s_; + size_t __idx_; + + __reference(_Storage& __s, size_t __idx) : __s_(__s), __idx_(__idx) {} + + _Vp __get() const { return __s_.__get(__idx_); } + + void __set(_Vp __v) { + if constexpr (is_same_v<_Vp, bool>) + __s_.__set(__idx_, __set_all_bits<_Tp>(__v)); + else + __s_.__set(__idx_, __v); + } + +public: + using value_type = _Vp; + + __reference() = delete; + __reference(const __reference&) = delete; + + operator value_type() const noexcept { return __get(); } +}; + +} // namespace parallelism_v2 +_LIBCPP_END_NAMESPACE_EXPERIMENTAL + +#endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) +#endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H diff --git a/libcxx/include/experimental/__simd/scalar.h b/libcxx/include/experimental/__simd/scalar.h --- a/libcxx/include/experimental/__simd/scalar.h +++ b/libcxx/include/experimental/__simd/scalar.h @@ -11,6 +11,7 @@ #define _LIBCPP_EXPERIMENTAL___SIMD_SCALAR_H #include +#include #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) @@ -20,8 +21,30 @@ struct __scalar { static constexpr size_t __simd_size = 1; }; - } // namespace simd_abi + +template +struct __simd_storage<_Tp, simd_abi::__scalar> { + _Tp __data; + + _Tp __get(size_t __idx) const noexcept { return (&__data)[__idx]; } + void __set(size_t __idx, _Tp __v) noexcept { (&__data)[__idx] = __v; } +}; + +template +struct __mask_storage<_Tp, simd_abi::__scalar> : __simd_storage {}; + +template +struct __simd_operations<_Tp, simd_abi::__scalar> { + using _Simd = __simd_storage<_Tp, simd_abi::__scalar>; + using _Mask = __mask_storage<_Tp, simd_abi::__scalar>; +}; + +template +struct __mask_operations<_Tp, simd_abi::__scalar> { + using _Mask = __mask_storage<_Tp, simd_abi::__scalar>; +}; + } // namespace parallelism_v2 _LIBCPP_END_NAMESPACE_EXPERIMENTAL diff --git a/libcxx/include/experimental/__simd/simd.h b/libcxx/include/experimental/__simd/simd.h --- a/libcxx/include/experimental/__simd/simd.h +++ b/libcxx/include/experimental/__simd/simd.h @@ -12,7 +12,10 @@ #include #include +#include +#include #include +#include #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) @@ -23,8 +26,14 @@ // TODO: implement simd class template class simd { + using _Impl = __simd_operations<_Tp, _Abi>; + using _Storage = typename _Impl::_Simd; + + _Storage __s_; + public: using value_type = _Tp; + using reference = __reference<_Tp, _Storage, value_type>; using mask_type = simd_mask<_Tp, _Abi>; using abi_type = _Abi; diff --git a/libcxx/include/experimental/__simd/simd_mask.h b/libcxx/include/experimental/__simd/simd_mask.h --- a/libcxx/include/experimental/__simd/simd_mask.h +++ b/libcxx/include/experimental/__simd/simd_mask.h @@ -12,6 +12,9 @@ #include #include +#include +#include +#include #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) @@ -22,8 +25,14 @@ // TODO: implement simd_mask class template class simd_mask { + using _Impl = __mask_operations<_Tp, _Abi>; + using _Storage = typename _Impl::_Mask; + + _Storage __s_; + public: using value_type = bool; + using reference = __reference<_Tp, _Storage, value_type>; using simd_type = simd<_Tp, _Abi>; using abi_type = _Abi; diff --git a/libcxx/include/experimental/__simd/utility.h b/libcxx/include/experimental/__simd/utility.h --- a/libcxx/include/experimental/__simd/utility.h +++ b/libcxx/include/experimental/__simd/utility.h @@ -15,6 +15,7 @@ #include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_same.h> #include <__type_traits/is_volatile.h> +#include #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) @@ -23,6 +24,36 @@ template constexpr bool __is_vectorizable_v = is_arithmetic_v<_Tp> && !is_const_v<_Tp> && !is_volatile_v<_Tp> && !is_same_v<_Tp, bool>; + +template +auto __choose_mask_type() { + if constexpr (sizeof(_Tp) == 1) { + return uint8_t{}; + } else if constexpr (sizeof(_Tp) == 2) { + return uint16_t{}; + } else if constexpr (sizeof(_Tp) == 4) { + return uint32_t{}; + } else if constexpr (sizeof(_Tp) == 8) { + return uint64_t{}; + } +# ifndef _LIBCPP_HAS_NO_INT128 + else if constexpr (sizeof(_Tp) == 16) { + return __uint128_t{}; + } +# endif + else + static_assert(sizeof(_Tp) == 0); +} + +template +auto constexpr __set_all_bits(bool __v) { + using _Up = decltype(__choose_mask_type<_Tp>()); + _Up __res = 0; + for (unsigned long __i = 0; __i < __CHAR_BIT__ * sizeof(_Tp); __i++) + __res |= static_cast<_Up>(__v) << __i; + return __res; +} + } // namespace parallelism_v2 _LIBCPP_END_NAMESPACE_EXPERIMENTAL diff --git a/libcxx/include/experimental/__simd/vec_ext.h b/libcxx/include/experimental/__simd/vec_ext.h --- a/libcxx/include/experimental/__simd/vec_ext.h +++ b/libcxx/include/experimental/__simd/vec_ext.h @@ -11,6 +11,8 @@ #define _LIBCPP_EXPERIMENTAL___SIMD_VEC_EXT_H #include +#include +#include #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) @@ -21,8 +23,31 @@ struct __vec_ext { static constexpr size_t __simd_size = _Np; }; - } // namespace simd_abi + +template +struct __simd_storage<_Tp, simd_abi::__vec_ext<_Np>> { + _Tp __data __attribute__((vector_size(sizeof(_Tp) * _Np))); + + _Tp __get(size_t __idx) const noexcept { return __data[__idx]; } + void __set(size_t __idx, _Tp __v) noexcept { __data[__idx] = __v; } +}; + +template +struct __mask_storage<_Tp, simd_abi::__vec_ext<_Np>> + : __simd_storage()), simd_abi::__vec_ext<_Np>> {}; + +template +struct __simd_operations<_Tp, simd_abi::__vec_ext<_Np>> { + using _Simd = __simd_storage<_Tp, simd_abi::__vec_ext<_Np>>; + using _Mask = __mask_storage<_Tp, simd_abi::__vec_ext<_Np>>; +}; + +template +struct __mask_operations<_Tp, simd_abi::__vec_ext<_Np>> { + using _Mask = __mask_storage<_Tp, simd_abi::__vec_ext<_Np>>; +}; + } // namespace parallelism_v2 _LIBCPP_END_NAMESPACE_EXPERIMENTAL diff --git a/libcxx/test/std/experimental/simd/simd.class/simd_alias.pass.cpp b/libcxx/test/std/experimental/simd/simd.class/simd_alias.pass.cpp --- a/libcxx/test/std/experimental/simd/simd.class/simd_alias.pass.cpp +++ b/libcxx/test/std/experimental/simd/simd.class/simd_alias.pass.cpp @@ -12,6 +12,7 @@ // template class simd { // public: // using value_type = T; +// using reference = see below; // using mask_type = simd_mask; // using abi_type = Abi; // }; @@ -26,6 +27,7 @@ template void operator()() { static_assert(std::is_same_v::value_type, T>); + static_assert(is_simd_reference::reference>::value); static_assert(std::is_same_v::mask_type, ex::simd_mask>); static_assert(std::is_same_v::abi_type, SimdAbi>); } diff --git a/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_alias.pass.cpp b/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_alias.pass.cpp --- a/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_alias.pass.cpp +++ b/libcxx/test/std/experimental/simd/simd.mask.class/simd_mask_alias.pass.cpp @@ -12,6 +12,7 @@ // template class simd_mask { // public: // using value_type = bool; +// using reference = see below; // using simd_type = simd; // using abi_type = Abi; // }; @@ -26,6 +27,7 @@ template void operator()() { static_assert(std::is_same_v::value_type, bool>); + static_assert(is_simd_reference::reference>::value); static_assert(std::is_same_v::simd_type, ex::simd>); static_assert(std::is_same_v::abi_type, SimdAbi>); } diff --git a/libcxx/test/std/experimental/simd/test_utils.h b/libcxx/test/std/experimental/simd/test_utils.h --- a/libcxx/test/std/experimental/simd/test_utils.h +++ b/libcxx/test/std/experimental/simd/test_utils.h @@ -50,4 +50,10 @@ return pow; } +template +struct is_simd_reference : std::false_type {}; + +template +struct is_simd_reference> : std::true_type {}; + #endif // TEST_UTIL_H