Vc 1.4.5
SIMD Vector Classes for C++
 
Loading...
Searching...
No Matches
interleavedmemory.h
1/* This file is part of the Vc library. {{{
2Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in the
10 documentation and/or other materials provided with the distribution.
11 * Neither the names of contributing organizations nor the
12 names of its contributors may be used to endorse or promote products
13 derived from this software without specific prior written permission.
14
15THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26}}}*/
27
28#ifndef VC_COMMON_INTERLEAVEDMEMORY_H_
29#define VC_COMMON_INTERLEAVEDMEMORY_H_
30
31#include "macros.h"
32
33namespace Vc_VERSIONED_NAMESPACE
34{
35namespace Common
36{
40template<typename V, typename I, bool Readonly> struct InterleavedMemoryAccessBase
41{
42 // Partial specialization doesn't work for functions without partial specialization of the whole
43 // class. Therefore we capture the contents of InterleavedMemoryAccessBase in a macro to easily
44 // copy it into its specializations.
45 typedef typename std::conditional<
46 Readonly, typename std::add_const<typename V::EntryType>::type,
47 typename V::EntryType>::type T;
48 typedef typename V::AsArg VArg;
49 typedef T Ta Vc_MAY_ALIAS;
50 const I m_indexes;
51 Ta *const m_data;
52
53 Vc_ALWAYS_INLINE InterleavedMemoryAccessBase(typename I::AsArg indexes, Ta *data)
54 : m_indexes(indexes), m_data(data)
55 {
56 }
57
58 // implementations of the following are in {scalar,sse,avx}/detail.h
59 template <typename... Vs> Vc_INTRINSIC void deinterleave(Vs &&... vs) const
60 {
61 Impl::deinterleave(m_data, m_indexes, std::forward<Vs>(vs)...);
62 }
63
64protected:
65 using Impl = Vc::Detail::InterleaveImpl<V, V::Size, sizeof(V)>;
66
67 template <typename T, std::size_t... Indexes>
68 Vc_INTRINSIC void callInterleave(T &&a, index_sequence<Indexes...>)
69 {
70 Impl::interleave(m_data, m_indexes, a[Indexes]...);
71 }
72};
73
77// delay execution of the deinterleaving gather until operator=
78template <size_t StructSize, typename V, typename I = typename V::IndexType,
79 bool Readonly>
80struct InterleavedMemoryReadAccess : public InterleavedMemoryAccessBase<V, I, Readonly>
81{
82 typedef InterleavedMemoryAccessBase<V, I, Readonly> Base;
83 typedef typename Base::Ta Ta;
84
85 Vc_ALWAYS_INLINE InterleavedMemoryReadAccess(Ta *data, typename I::AsArg indexes)
86 : Base(StructSize == 1u
87 ? indexes
88 : StructSize == 2u
89 ? indexes << 1
90 : StructSize == 4u
91 ? indexes << 2
92 : StructSize == 8u
93 ? indexes << 3
94 : StructSize == 16u ? indexes << 4
95 : indexes * I(int(StructSize)),
96 data)
97 {
98 }
99
100 template <typename T, std::size_t... Indexes>
101 Vc_ALWAYS_INLINE T deinterleave_unpack(index_sequence<Indexes...>) const
102 {
103 T r;
104 Base::Impl::deinterleave(this->m_data, this->m_indexes, std::get<Indexes>(r)...);
105 return r;
106 }
107
108 template <typename T,
109 typename = enable_if<(std::is_default_constructible<T>::value &&
110 std::is_same<V, Traits::decay<decltype(std::get<0>(
111 std::declval<T &>()))>>::value)>>
112 Vc_ALWAYS_INLINE operator T() const
113 {
114 return deinterleave_unpack<T>(make_index_sequence<std::tuple_size<T>::value>());
115 }
116};
117
119template<typename I> struct CheckIndexesUnique
120{
121#ifdef NDEBUG
122 static Vc_INTRINSIC void test(const I &) {}
123#else
124 static void test(const I &indexes)
125 {
126 const I test = indexes.sorted();
127 Vc_ASSERT(I::Size == 1 || (test == test.rotated(1)).isEmpty())
128 }
129#endif
130};
132template<size_t S> struct CheckIndexesUnique<SuccessiveEntries<S> >
133{
134 static Vc_INTRINSIC void test(const SuccessiveEntries<S> &) {}
135};
136
140template <size_t StructSize, typename V, typename I = typename V::IndexType>
141struct InterleavedMemoryAccess : public InterleavedMemoryReadAccess<StructSize, V, I, false>
142{
143 typedef InterleavedMemoryAccessBase<V, I, false> Base;
144 typedef typename Base::Ta Ta;
145
146 Vc_ALWAYS_INLINE InterleavedMemoryAccess(Ta *data, typename I::AsArg indexes)
147 : InterleavedMemoryReadAccess<StructSize, V, I, false>(data, indexes)
148 {
149 CheckIndexesUnique<I>::test(indexes);
150 }
151
152 template <int N> Vc_ALWAYS_INLINE void operator=(VectorReferenceArray<N, V> &&rhs)
153 {
154 static_assert(N <= StructSize,
155 "You_are_trying_to_scatter_more_data_into_the_struct_than_it_has");
156 this->callInterleave(std::move(rhs), make_index_sequence<N>());
157 }
158 template <int N> Vc_ALWAYS_INLINE void operator=(VectorReferenceArray<N, const V> &&rhs)
159 {
160 static_assert(N <= StructSize,
161 "You_are_trying_to_scatter_more_data_into_the_struct_than_it_has");
162 this->callInterleave(std::move(rhs), make_index_sequence<N>());
163 }
164};
165
177template<typename S, typename V> class InterleavedMemoryWrapper
178{
179 typedef typename std::conditional<std::is_const<S>::value,
180 const typename V::EntryType,
181 typename V::EntryType>::type T;
182 typedef typename V::IndexType I;
183 typedef typename V::AsArg VArg;
184 typedef const I &IndexType;
185 static constexpr std::size_t StructSize = sizeof(S) / sizeof(T);
186 using ReadAccess = InterleavedMemoryReadAccess<StructSize, V>;
187 using Access =
188 typename std::conditional<std::is_const<T>::value, ReadAccess,
189 InterleavedMemoryAccess<StructSize, V>>::type;
190 using ReadSuccessiveEntries =
191 InterleavedMemoryReadAccess<StructSize, V, SuccessiveEntries<StructSize>>;
192 using AccessSuccessiveEntries = typename std::conditional<
193 std::is_const<T>::value, ReadSuccessiveEntries,
194 InterleavedMemoryAccess<StructSize, V, SuccessiveEntries<StructSize>>>::type;
195 typedef T Ta Vc_MAY_ALIAS;
196 Ta *const m_data;
197
198 static_assert(StructSize * sizeof(T) == sizeof(S),
199 "InterleavedMemoryAccess_does_not_support_packed_structs");
200
201public:
207 Vc_ALWAYS_INLINE InterleavedMemoryWrapper(S *s)
208 : m_data(reinterpret_cast<Ta *>(s))
209 {
210 }
211
264 template <typename IT>
265 Vc_ALWAYS_INLINE enable_if<!std::is_convertible<IT, size_t>::value &&
266 std::is_convertible<IT, IndexType>::value &&
267 !std::is_const<S>::value,
268 Access>
269 operator[](IT indexes)
270 {
271 return Access(m_data, indexes);
272 }
273
275 Vc_ALWAYS_INLINE ReadAccess operator[](IndexType indexes) const
276 {
277 return ReadAccess(m_data, indexes);
278 }
279
281 Vc_ALWAYS_INLINE ReadAccess gather(IndexType indexes) const { return operator[](indexes); }
282
316 Vc_ALWAYS_INLINE ReadSuccessiveEntries operator[](size_t first) const
317 {
318 return ReadSuccessiveEntries(m_data, first);
319 }
320
321 Vc_ALWAYS_INLINE AccessSuccessiveEntries operator[](size_t first)
322 {
323 return AccessSuccessiveEntries(m_data, first);
324 }
325
326 //Vc_ALWAYS_INLINE Access scatter(I indexes, VArg v0, VArg v1);
327};
328} // namespace Common
329
330using Common::InterleavedMemoryWrapper;
331
344template <typename V, typename S>
349} // namespace Vc
350
351#endif // VC_COMMON_INTERLEAVEDMEMORY_H_
Wraps a pointer to memory with convenience functions to access it via vectors.
ReadAccess gather(IndexType indexes) const
alias of the above function
ReadSuccessiveEntries operator[](size_t first) const
Interleaved access.
ReadAccess operator[](IndexType indexes) const
const overload (gathers only) of the above function
enable_if<!std::is_convertible< IT, size_t >::value &&std::is_convertible< IT, IndexType >::value &&!std::is_const< S >::value, Access > operator[](IT indexes)
InterleavedMemoryWrapper(S *s)
Constructs the wrapper object.
void deinterleave(V *a, V *b, const M *memory, A align)
Common::InterleavedMemoryWrapper< S, V > make_interleave_wrapper(S *s)
Creates an adapter around a given array of structure (AoS) that enables optimized loads.