native 0.0.1
Vectors, masks and wide register packs for C++26
Loading...
Searching...
No Matches
common_body.h
1namespace native {
2namespace detail {
3#ifdef NATIVE_ARCH_REQUIRES
4 template<class T, std::size_t N, ::native::isa<> Arch, std::size_t L> requires NATIVE_ARCH_REQUIRES(Arch)
5 struct register_memory<simd<T,N,Arch>,L> {
6 using V=simd<T,N,Arch>;
7 static constexpr std::size_t lanes = L;
8 native_nodiscard static native_inline constexpr native_pure V load_partial(native_noescape float const * p, std::size_t n, float fill = 0) noexcept native_diagnose_if(n > L,"partial SIMD count exceeds the lane count") {
9 alignas(64) std::array<float, L> a; a.fill(fill);
10 for (std::size_t i = 0; i < n; ++i) a[i] = p[i];
11 return V::load(a.data());
12 }
13 native_inline constexpr void store_partial(native_noescape float * p, std::size_t n) const noexcept native_diagnose_if(n > L,"partial SIMD count exceeds the lane count") {
14 alignas(64) std::array<float, L> a; static_cast<V const &>(*this).store(a.data());
15 for (std::size_t i = 0; i < n; ++i) p[i] = a[i];
16 }
17 };
18#endif
19
20}
21 template<simd_custom_element T, std::size_t N, isa<> Arch> requires NATIVE_COMMON_ARCH(Arch)
22 struct native_empty_bases simd<T,N,Arch> : simd_customization<T,
23 simd<typename simd_traits<T>::storage_type,N,Arch>,simd<T,N,Arch>>, detail::swizzle_access<T,N,Arch> {
25 using base::base;
27 native_inline constexpr simd() = default;
28 static constexpr isa<> architecture=Arch;
29 using mask = typename simd<typename simd_traits<T>::storage_type,N,Arch>::mask;
30 using mask_type = mask;
31 using predicate_type = predicate<N,Arch>;
32 template<class U> using rebind = simd<U,N,Arch>;
33 };
34
38 template <class V, class U, std::size_t A=1, simd_access Access=simd_access::ordinary>
39 requires detail::memory_architecture<V,U>::known && NATIVE_COMMON_ARCH(detail::memory_architecture_v<V,U>) && requires(U const * p) { V::template load_memory<A>(p); }
41 noexcept(noexcept(V::template load_memory<A>(p))) {
42 return V::template load_memory<A>(p);
43 }
44
47 template <class V, simd_custom_element U, std::size_t A=1, simd_access Access=simd_access::ordinary>
48 requires detail::memory_architecture<V,U>::known && NATIVE_COMMON_ARCH(detail::memory_architecture_v<V,U>) && std::same_as<typename V::value_type,typename simd_traits<U>::storage_type>
50 noexcept(noexcept(V::template rebind<U>::template load_memory<A>(p).to_native())) {
51 return V::template rebind<U>::template load_memory<A>(p).to_native();
52 }
53
56 template <class U, class V, std::size_t A=1, simd_access Access=simd_access::ordinary>
57 requires detail::memory_architecture<V,U>::known && NATIVE_COMMON_ARCH(detail::memory_architecture_v<V,U>) && requires(V value,U * p) { value.template store_memory<A>(p); }
58 native_inline constexpr void store_simd(U * p,V value,simd_memory<A,Access> = {})
59 noexcept(noexcept(value.template store_memory<A>(p))) {
60 value.template store_memory<A>(p);
61 }
62
65 template <simd_custom_element U, class V, std::size_t A=1, simd_access Access=simd_access::ordinary>
66 requires detail::memory_architecture<V,U>::known && NATIVE_COMMON_ARCH(detail::memory_architecture_v<V,U>) && std::same_as<typename V::value_type,typename simd_traits<U>::storage_type>
67 native_inline constexpr void store_simd(U * p,V value,simd_memory<A,Access> = {})
68 noexcept(noexcept(typename V::template rebind<U>(value).template store_memory<A>(p))) {
69 typename V::template rebind<U>(value).template store_memory<A>(p);
70 }
71
73 template<class V,class U,std::size_t N> requires detail::memory_architecture<V,U>::known && NATIVE_COMMON_ARCH(detail::memory_architecture_v<V,U>) &&(N==V::lanes) &&
74 requires(U const * p) { ::native::load_simd<V>(p); }
75 native_nodiscard native_inline constexpr V load_simd(std::array<U,N> const & values)
76 noexcept(noexcept(::native::load_simd<V>(values.data()))) {
77 return ::native::load_simd<V>(values.data());
78 }
79
81 template<class V,class U,std::size_t N> requires detail::memory_architecture<V,U>::known && NATIVE_COMMON_ARCH(detail::memory_architecture_v<V,U>) &&(N==V::lanes) &&
82 requires(U * p) { ::native::load_simd<V>(p); }
83 native_nodiscard native_inline constexpr V load_simd(std::span<U,N> values)
84 noexcept(noexcept(::native::load_simd<V>(values.data()))) {
85 return ::native::load_simd<V>(values.data());
86 }
87
92 template <class V, class U, std::size_t A=1, simd_access Access=simd_access::ordinary>
93 requires detail::memory_architecture<V,U>::known && NATIVE_COMMON_ARCH(detail::memory_architecture_v<V,U>) && std::default_initializable<U> &&
94 std::constructible_from<U,typename V::value_type &> && std::is_copy_assignable_v<U> &&
95 requires(U const * p) { ::native::load_simd<V>(p); }
96 native_nodiscard native_inline constexpr V load_simd_partial(U const * p,std::size_t count,
97 typename V::value_type fill={},simd_memory<A,Access> = {})
98 noexcept(std::is_nothrow_default_constructible_v<U> &&
99 std::is_nothrow_constructible_v<U,typename V::value_type &> &&
100 std::is_nothrow_copy_assignable_v<U> && noexcept(::native::load_simd<V>(p))) native_diagnose_if(count > V::lanes,"partial SIMD count exceeds the lane count") {
101 std::array<U,V::lanes> temporary; temporary.fill(U(fill));
102 for(std::size_t i=0;i<count;++i) temporary[i]=p[i];
103 return ::native::load_simd<V>(temporary.data());
104 }
105
109 template <class U, class V, std::size_t A=1, simd_access Access=simd_access::ordinary>
110 requires detail::memory_architecture<V,U>::known && NATIVE_COMMON_ARCH(detail::memory_architecture_v<V,U>) && std::default_initializable<U> && std::is_copy_assignable_v<U> &&
111 requires(U * p,V value) { ::native::store_simd(p,value); }
112 native_inline constexpr void store_simd_partial(U * p,V value,std::size_t count,simd_memory<A,Access> = {})
113 noexcept(std::is_nothrow_default_constructible_v<U> &&
114 std::is_nothrow_copy_assignable_v<U> && noexcept(::native::store_simd(p,value))) native_diagnose_if(count > V::lanes,"partial SIMD count exceeds the lane count") {
115 std::array<U,V::lanes> temporary; ::native::store_simd(temporary.data(),value);
116 for(std::size_t i=0;i<count;++i) p[i]=temporary[i];
117 }
118
119}
#define native_diagnose_if(condition, message)
Reject a call when Clang can prove that its arguments violate a precondition.
Definition attributes.h:50
#define native_inline
inline [[always_inline]]
Definition attributes.h:212
#define native_noescape
portable __attribute__((noescape))
Definition attributes.h:175
#define native_nodiscard
C++17 [[nodiscard]].
Definition attributes.h:189
#define native_pure
[[pure]]
Definition attributes.h:126
constexpr void store_simd(U *p, V value, simd_memory< A, Access >={}) noexcept(noexcept(value.template store_memory< A >(p)))
Definition common_body.h:58
constexpr V load_simd(U const *p, simd_memory< A, Access >={}) noexcept(noexcept(V::template load_memory< A >(p)))
Definition common_body.h:40
constexpr V load_simd_partial(U const *p, std::size_t count, typename V::value_type fill={}, simd_memory< A, Access >={}) noexcept(std::is_nothrow_default_constructible_v< U > &&std::is_nothrow_constructible_v< U, typename V::value_type & > &&std::is_nothrow_copy_assignable_v< U > &&noexcept(::native::load_simd< V >(p)))
Definition common_body.h:96
constexpr void store_simd_partial(U *p, V value, std::size_t count, simd_memory< A, Access >={}) noexcept(std::is_nothrow_default_constructible_v< U > &&std::is_nothrow_copy_assignable_v< U > &&noexcept(::native::store_simd(p, value)))
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
constexpr simd()=default
Default-construct the element customization; its initialization contract is retained.