Vc  1.3.80-dev
SIMD Vector Classes for C++
interleavedmemory.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2012-2015 Matthias Kretz <kretz@kde.org>
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, 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 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON 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
24 SOFTWARE, 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 
33 namespace Vc_VERSIONED_NAMESPACE
34 {
35 namespace Common
36 {
40 template<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 
64 protected:
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=
78 template <size_t StructSize, typename V, typename I = typename V::IndexType,
79  bool Readonly>
80 struct 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 
119 template<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 };
132 template<size_t S> struct CheckIndexesUnique<SuccessiveEntries<S> >
133 {
134  static Vc_INTRINSIC void test(const SuccessiveEntries<S> &) {}
135 };
136 
140 template <size_t StructSize, typename V, typename I = typename V::IndexType>
141 struct 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 
177 template<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  typedef InterleavedMemoryAccess<StructSize, V> Access;
187  typedef InterleavedMemoryReadAccess<StructSize, V> ReadAccess;
188  typedef InterleavedMemoryAccess<StructSize, V, SuccessiveEntries<StructSize> > AccessSuccessiveEntries;
189  typedef InterleavedMemoryReadAccess<StructSize, V, SuccessiveEntries<StructSize> > ReadSuccessiveEntries;
190  typedef T Ta Vc_MAY_ALIAS;
191  Ta *const m_data;
192 
193  static_assert(StructSize * sizeof(T) == sizeof(S),
194  "InterleavedMemoryAccess_does_not_support_packed_structs");
195 
196 public:
202  Vc_ALWAYS_INLINE InterleavedMemoryWrapper(S *s)
203  : m_data(reinterpret_cast<Ta *>(s))
204  {
205  }
206 
259  template <typename IT>
260  Vc_ALWAYS_INLINE enable_if<!std::is_convertible<IT, size_t>::value &&
261  std::is_convertible<IT, IndexType>::value &&
262  !std::is_const<S>::value,
263  Access>
264  operator[](IT indexes)
265  {
266  return Access(m_data, indexes);
267  }
268 
270  Vc_ALWAYS_INLINE ReadAccess operator[](IndexType indexes) const
271  {
272  return ReadAccess(m_data, indexes);
273  }
274 
276  Vc_ALWAYS_INLINE ReadAccess gather(IndexType indexes) const { return operator[](indexes); }
277 
311  Vc_ALWAYS_INLINE ReadSuccessiveEntries operator[](size_t first) const
312  {
313  return ReadSuccessiveEntries(m_data, first);
314  }
315 
316  Vc_ALWAYS_INLINE AccessSuccessiveEntries operator[](size_t first)
317  {
318  return AccessSuccessiveEntries(m_data, first);
319  }
320 
321  //Vc_ALWAYS_INLINE Access scatter(I indexes, VArg v0, VArg v1);
322 };
323 } // namespace Common
324 
326 
327 template <typename V, typename S>
328 inline Common::InterleavedMemoryWrapper<S, V> make_interleave_wrapper(S *s)
329 {
331 }
332 } // namespace Vc
333 
334 #endif // VC_COMMON_INTERLEAVEDMEMORY_H_
enable_if<!std::is_convertible< IT, size_t >::value &&std::is_convertible< IT, IndexType >::value &&!std::is_const< S >::value, Access > operator[](IT indexes)
Interleaved scatter/gather access.
Wraps a pointer to memory with convenience functions to access it via vectors.
ReadAccess operator[](IndexType indexes) const
const overload (gathers only) of the above function
InterleavedMemoryWrapper(S *s)
Constructs the wrapper object.
void deinterleave(V *a, V *b, const M *memory, A align)
Definition: deinterleave.h:76
ReadAccess gather(IndexType indexes) const
alias of the above function
std::pair< V, V > interleave(const V &a, const V &b)
Interleaves the entries from a and b into two vectors of the same type.
Definition: interleave.h:55
ReadSuccessiveEntries operator[](size_t first) const
Interleaved access.