xref: /llvm-project/libcxx/include/experimental/__simd/simd.h (revision f69585235ec85d54e0f3fc41b2d5700430907f99)
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