10e30dd44SZhangyin // -*- C++ -*- 20e30dd44SZhangyin //===----------------------------------------------------------------------===// 30e30dd44SZhangyin // 40e30dd44SZhangyin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 50e30dd44SZhangyin // See https://llvm.org/LICENSE.txt for license information. 60e30dd44SZhangyin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 70e30dd44SZhangyin // 80e30dd44SZhangyin //===----------------------------------------------------------------------===// 90e30dd44SZhangyin 100e30dd44SZhangyin #ifndef _LIBCPP_EXPERIMENTAL___SIMD_SIMD_H 110e30dd44SZhangyin #define _LIBCPP_EXPERIMENTAL___SIMD_SIMD_H 120e30dd44SZhangyin 13118f120eSLouis Dionne #include <__config> 14e99c4906SNikolas Klauser #include <__cstddef/size_t.h> 15d6832a61SLouis Dionne #include <__type_traits/enable_if.h> 162c3d7d53SZhangYin #include <__type_traits/is_integral.h> 171314e877Sphilnik777 #include <__type_traits/is_same.h> 18ed29f275SZhangyin #include <__type_traits/remove_cvref.h> 191314e877Sphilnik777 #include <__utility/forward.h> 20ce5652c7SZhangyin #include <experimental/__simd/declaration.h> 21e7a45c6dSZhangyin #include <experimental/__simd/reference.h> 22ce5652c7SZhangyin #include <experimental/__simd/traits.h> 231314e877Sphilnik777 #include <experimental/__simd/utility.h> 240e30dd44SZhangyin 250e30dd44SZhangyin #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) 260e30dd44SZhangyin 270e30dd44SZhangyin _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL 280e30dd44SZhangyin inline namespace parallelism_v2 { 290e30dd44SZhangyin 302c3d7d53SZhangYin template <class _Simd, class _Impl, bool> 312c3d7d53SZhangYin class __simd_int_operators {}; 322c3d7d53SZhangYin 332c3d7d53SZhangYin template <class _Simd, class _Impl> 342c3d7d53SZhangYin class __simd_int_operators<_Simd, _Impl, true> { 352c3d7d53SZhangYin public: 362c3d7d53SZhangYin // unary operators for integral _Tp 372c3d7d53SZhangYin _LIBCPP_HIDE_FROM_ABI _Simd operator~() const noexcept { 382c3d7d53SZhangYin return _Simd(_Impl::__bitwise_not((*static_cast<const _Simd*>(this)).__s_), _Simd::__storage_tag); 392c3d7d53SZhangYin } 402c3d7d53SZhangYin }; 412c3d7d53SZhangYin 420e30dd44SZhangyin // class template simd [simd.class] 430e30dd44SZhangyin // TODO: implement simd class 44ce5652c7SZhangyin template <class _Tp, class _Abi> 452c3d7d53SZhangYin class simd : public __simd_int_operators<simd<_Tp, _Abi>, __simd_operations<_Tp, _Abi>, is_integral_v<_Tp>> { 46*f6958523SNikolas Klauser using _Impl _LIBCPP_NODEBUG = __simd_operations<_Tp, _Abi>; 47*f6958523SNikolas Klauser using _Storage _LIBCPP_NODEBUG = typename _Impl::_SimdStorage; 48e7a45c6dSZhangyin 49e7a45c6dSZhangyin _Storage __s_; 50e7a45c6dSZhangyin 512c3d7d53SZhangYin friend class __simd_int_operators<simd, _Impl, true>; 522c3d7d53SZhangYin 53ce5652c7SZhangyin public: 54ce5652c7SZhangyin using value_type = _Tp; 55e7a45c6dSZhangyin using reference = __simd_reference<_Tp, _Storage, value_type>; 56ce5652c7SZhangyin using mask_type = simd_mask<_Tp, _Abi>; 57ce5652c7SZhangyin using abi_type = _Abi; 58ce5652c7SZhangyin 59ce5652c7SZhangyin static _LIBCPP_HIDE_FROM_ABI constexpr size_t size() noexcept { return simd_size_v<value_type, abi_type>; } 60ed29f275SZhangyin 61e3c2eacfSZhangYin _LIBCPP_HIDE_FROM_ABI simd() noexcept = default; 62e3c2eacfSZhangYin 632c3d7d53SZhangYin // explicit conversion from and to implementation-defined types 642c3d7d53SZhangYin struct __storage_tag_t {}; 652c3d7d53SZhangYin static constexpr __storage_tag_t __storage_tag{}; 662c3d7d53SZhangYin explicit _LIBCPP_HIDE_FROM_ABI operator _Storage() const { return __s_; } 672c3d7d53SZhangYin explicit _LIBCPP_HIDE_FROM_ABI simd(const _Storage& __s, __storage_tag_t) : __s_(__s) {} 682c3d7d53SZhangYin 69ed29f275SZhangyin // broadcast constructor 70ed29f275SZhangyin template <class _Up, enable_if_t<__can_broadcast_v<value_type, __remove_cvref_t<_Up>>, int> = 0> 71ed29f275SZhangyin _LIBCPP_HIDE_FROM_ABI simd(_Up&& __v) noexcept : __s_(_Impl::__broadcast(static_cast<value_type>(__v))) {} 72ed29f275SZhangyin 73ba89749cSZhangYin // implicit type conversion constructor 74ba89749cSZhangYin template <class _Up, 75ba89749cSZhangYin enable_if_t<!is_same_v<_Up, _Tp> && is_same_v<abi_type, simd_abi::fixed_size<size()>> && 76ba89749cSZhangYin __is_non_narrowing_convertible_v<_Up, value_type>, 77ba89749cSZhangYin int> = 0> 78ba89749cSZhangYin _LIBCPP_HIDE_FROM_ABI simd(const simd<_Up, simd_abi::fixed_size<size()>>& __v) noexcept { 79ba89749cSZhangYin for (size_t __i = 0; __i < size(); __i++) { 80ba89749cSZhangYin (*this)[__i] = static_cast<value_type>(__v[__i]); 81ba89749cSZhangYin } 82ba89749cSZhangYin } 83ba89749cSZhangYin 84593521b0SZhangYin // generator constructor 85593521b0SZhangYin template <class _Generator, enable_if_t<__can_generate_v<value_type, _Generator, size()>, int> = 0> 86dc534106SZhangYin explicit _LIBCPP_HIDE_FROM_ABI simd(_Generator&& __g) noexcept 87dc534106SZhangYin : __s_(_Impl::__generate(std::forward<_Generator>(__g))) {} 88593521b0SZhangYin 896bb5c989SZhangYin // load constructor 906bb5c989SZhangYin template <class _Up, class _Flags, enable_if_t<__is_vectorizable_v<_Up> && is_simd_flag_type_v<_Flags>, int> = 0> 916bb5c989SZhangYin _LIBCPP_HIDE_FROM_ABI simd(const _Up* __mem, _Flags) { 926bb5c989SZhangYin _Impl::__load(__s_, _Flags::template __apply<simd>(__mem)); 936bb5c989SZhangYin } 946bb5c989SZhangYin 95058e4454SZhangYin // copy functions 96058e4454SZhangYin template <class _Up, class _Flags, enable_if_t<__is_vectorizable_v<_Up> && is_simd_flag_type_v<_Flags>, int> = 0> 97058e4454SZhangYin _LIBCPP_HIDE_FROM_ABI void copy_from(const _Up* __mem, _Flags) { 98058e4454SZhangYin _Impl::__load(__s_, _Flags::template __apply<simd>(__mem)); 99058e4454SZhangYin } 100058e4454SZhangYin 101058e4454SZhangYin template <class _Up, class _Flags, enable_if_t<__is_vectorizable_v<_Up> && is_simd_flag_type_v<_Flags>, int> = 0> 102058e4454SZhangYin _LIBCPP_HIDE_FROM_ABI void copy_to(_Up* __mem, _Flags) const { 103058e4454SZhangYin _Impl::__store(__s_, _Flags::template __apply<simd>(__mem)); 104058e4454SZhangYin } 105058e4454SZhangYin 106ed29f275SZhangyin // scalar access [simd.subscr] 107dc534106SZhangYin _LIBCPP_HIDE_FROM_ABI reference operator[](size_t __i) noexcept { return reference(__s_, __i); } 108dc534106SZhangYin _LIBCPP_HIDE_FROM_ABI value_type operator[](size_t __i) const noexcept { return __s_.__get(__i); } 1092c3d7d53SZhangYin 1102c3d7d53SZhangYin // simd unary operators 1112c3d7d53SZhangYin _LIBCPP_HIDE_FROM_ABI simd& operator++() noexcept { 1122c3d7d53SZhangYin _Impl::__increment(__s_); 1132c3d7d53SZhangYin return *this; 1142c3d7d53SZhangYin } 1152c3d7d53SZhangYin 1162c3d7d53SZhangYin _LIBCPP_HIDE_FROM_ABI simd operator++(int) noexcept { 1172c3d7d53SZhangYin simd __r = *this; 1182c3d7d53SZhangYin _Impl::__increment(__s_); 1192c3d7d53SZhangYin return __r; 1202c3d7d53SZhangYin } 1212c3d7d53SZhangYin 1222c3d7d53SZhangYin _LIBCPP_HIDE_FROM_ABI simd& operator--() noexcept { 1232c3d7d53SZhangYin _Impl::__decrement(__s_); 1242c3d7d53SZhangYin return *this; 1252c3d7d53SZhangYin } 1262c3d7d53SZhangYin 1272c3d7d53SZhangYin _LIBCPP_HIDE_FROM_ABI simd operator--(int) noexcept { 1282c3d7d53SZhangYin simd __r = *this; 1292c3d7d53SZhangYin _Impl::__decrement(__s_); 1302c3d7d53SZhangYin return __r; 1312c3d7d53SZhangYin } 1322c3d7d53SZhangYin 1332c3d7d53SZhangYin _LIBCPP_HIDE_FROM_ABI mask_type operator!() const noexcept { 1342c3d7d53SZhangYin return mask_type(_Impl::__negate(__s_), mask_type::__storage_tag); 1352c3d7d53SZhangYin } 1362c3d7d53SZhangYin 1372c3d7d53SZhangYin _LIBCPP_HIDE_FROM_ABI simd operator+() const noexcept { return *this; } 1382c3d7d53SZhangYin 1392c3d7d53SZhangYin _LIBCPP_HIDE_FROM_ABI simd operator-() const noexcept { return simd(_Impl::__unary_minus(__s_), __storage_tag); } 140ce5652c7SZhangyin }; 1410e30dd44SZhangyin 1421314e877Sphilnik777 template <class _Tp, class _Abi> 1431314e877Sphilnik777 inline constexpr bool is_simd_v<simd<_Tp, _Abi>> = true; 1441314e877Sphilnik777 1450e30dd44SZhangyin template <class _Tp> 1460e30dd44SZhangyin using native_simd = simd<_Tp, simd_abi::native<_Tp>>; 1470e30dd44SZhangyin 1480e30dd44SZhangyin template <class _Tp, int _Np> 1490e30dd44SZhangyin using fixed_size_simd = simd<_Tp, simd_abi::fixed_size<_Np>>; 1500e30dd44SZhangyin 1510e30dd44SZhangyin } // namespace parallelism_v2 1520e30dd44SZhangyin _LIBCPP_END_NAMESPACE_EXPERIMENTAL 1530e30dd44SZhangyin 1540e30dd44SZhangyin #endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) 1550e30dd44SZhangyin #endif // _LIBCPP_EXPERIMENTAL___SIMD_SIMD_H 156