Vc  1.3.2-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<
261  std::is_convertible<IT, IndexType>::value && !std::is_const<S>::value, Access>
262  operator[](IT indexes)
263  {
264  return Access(m_data, indexes);
265  }
266 
268  Vc_ALWAYS_INLINE ReadAccess operator[](IndexType indexes) const
269  {
270  return ReadAccess(m_data, indexes);
271  }
272 
274  Vc_ALWAYS_INLINE ReadAccess gather(IndexType indexes) const { return operator[](indexes); }
275 
309  Vc_ALWAYS_INLINE ReadSuccessiveEntries operator[](size_t first) const
310  {
311  return ReadSuccessiveEntries(m_data, first);
312  }
313 
314  Vc_ALWAYS_INLINE AccessSuccessiveEntries operator[](size_t first)
315  {
316  return AccessSuccessiveEntries(m_data, first);
317  }
318 
319  //Vc_ALWAYS_INLINE Access scatter(I indexes, VArg v0, VArg v1);
320 };
321 } // namespace Common
322 
323 using Common::InterleavedMemoryWrapper;
324 
325 template <typename V, typename S>
326 inline Common::InterleavedMemoryWrapper<S, V> make_interleave_wrapper(S *s)
327 {
328  return Common::InterleavedMemoryWrapper<S, V>(s);
329 }
330 } // namespace Vc
331 
332 #endif // VC_COMMON_INTERLEAVEDMEMORY_H_
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
enable_if< std::is_convertible< IT, IndexType >::value &&!std::is_const< S >::value, Access > operator[](IT indexes)
Interleaved scatter/gather access.
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.