Vc  1.3.2-dev
SIMD Vector Classes for C++
storage.h
1 /* This file is part of the Vc library. {{{
2 Copyright © 2010-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_STORAGE_H_
29 #define VC_COMMON_STORAGE_H_
30 
31 #include "aliasingentryhelper.h"
32 #include "types.h"
33 #include "maskbool.h"
34 #ifdef Vc_IMPL_AVX
35 #include "../avx/intrinsics.h"
36 #endif
37 #include "macros.h"
38 
39 namespace Vc_VERSIONED_NAMESPACE
40 {
41 namespace Detail
42 {
43 template <typename V> inline V zero();
44 } // namespace Detail
45 namespace Common
46 {
47 namespace Detail
48 {
49 #ifdef Vc_IMPL_AVX
50 template <typename ValueType, size_t Size> struct IntrinsicType {
51  using type = typename std::conditional<
52  std::is_integral<ValueType>::value,
53  typename std::conditional<sizeof(ValueType) * Size == 16, __m128i, __m256i>::type,
54  typename std::conditional<
55  std::is_same<ValueType, double>::value,
56  typename std::conditional<sizeof(ValueType) * Size == 16, __m128d,
57  __m256d>::type,
58  typename std::conditional<sizeof(ValueType) * Size == 16, __m128,
59  __m256>::type>::type>::type;
60 };
61 #elif defined Vc_IMPL_SSE
62 template <typename ValueType, size_t Size> struct IntrinsicType {
63  using type = typename std::conditional<
64  std::is_integral<ValueType>::value, __m128i,
65  typename std::conditional<std::is_same<ValueType, double>::value, __m128d,
66  __m128>::type>::type;
67 };
68 #elif defined Vc_IMPL_MIC
69 template <typename ValueType, size_t Size> struct IntrinsicType {
70  using type = typename std::conditional<
71  std::is_integral<ValueType>::value, __m512i,
72  typename std::conditional<std::is_same<ValueType, double>::value, __m512d,
73  __m512>::type>::type;
74 };
75 #else
76 template <typename ValueType, size_t Size> struct IntrinsicType {
77  static_assert(Size == 1,
78  "IntrinsicType without SIMD target support may only have Size = 1");
79  using type = ValueType;
80 };
81 #endif
82 template <typename ValueType, size_t Size, size_t Bytes = sizeof(ValueType) * Size>
83 struct BuiltinType;
84 #ifdef Vc_USE_BUILTIN_VECTOR_TYPES
85 #define Vc_VECBUILTIN __attribute__((__vector_size__(16)))
86 template <size_t Size> struct BuiltinType< double , Size, 16> { typedef double type Vc_VECBUILTIN; };
87 template <size_t Size> struct BuiltinType< float , Size, 16> { typedef float type Vc_VECBUILTIN; };
88 template <size_t Size> struct BuiltinType< long long, Size, 16> { typedef long long type Vc_VECBUILTIN; };
89 template <size_t Size> struct BuiltinType<unsigned long long, Size, 16> { typedef unsigned long long type Vc_VECBUILTIN; };
90 template <size_t Size> struct BuiltinType< long , Size, 16> { typedef long type Vc_VECBUILTIN; };
91 template <size_t Size> struct BuiltinType<unsigned long , Size, 16> { typedef unsigned long type Vc_VECBUILTIN; };
92 template <size_t Size> struct BuiltinType< int , Size, 16> { typedef int type Vc_VECBUILTIN; };
93 template <size_t Size> struct BuiltinType<unsigned int , Size, 16> { typedef unsigned int type Vc_VECBUILTIN; };
94 template <size_t Size> struct BuiltinType< short , Size, 16> { typedef short type Vc_VECBUILTIN; };
95 template <size_t Size> struct BuiltinType<unsigned short , Size, 16> { typedef unsigned short type Vc_VECBUILTIN; };
96 template <size_t Size> struct BuiltinType< char , Size, 16> { typedef char type Vc_VECBUILTIN; };
97 template <size_t Size> struct BuiltinType<unsigned char , Size, 16> { typedef unsigned char type Vc_VECBUILTIN; };
98 template <size_t Size> struct BuiltinType< signed char , Size, 16> { typedef signed char type Vc_VECBUILTIN; };
99 template <size_t Size> struct BuiltinType< bool , Size, 16> { typedef unsigned char type Vc_VECBUILTIN; };
100 #undef Vc_VECBUILTIN
101 #define Vc_VECBUILTIN __attribute__((__vector_size__(32)))
102 template <size_t Size> struct BuiltinType< double , Size, 32> { typedef double type Vc_VECBUILTIN; };
103 template <size_t Size> struct BuiltinType< float , Size, 32> { typedef float type Vc_VECBUILTIN; };
104 template <size_t Size> struct BuiltinType< long long, Size, 32> { typedef long long type Vc_VECBUILTIN; };
105 template <size_t Size> struct BuiltinType<unsigned long long, Size, 32> { typedef unsigned long long type Vc_VECBUILTIN; };
106 template <size_t Size> struct BuiltinType< long , Size, 32> { typedef long type Vc_VECBUILTIN; };
107 template <size_t Size> struct BuiltinType<unsigned long , Size, 32> { typedef unsigned long type Vc_VECBUILTIN; };
108 template <size_t Size> struct BuiltinType< int , Size, 32> { typedef int type Vc_VECBUILTIN; };
109 template <size_t Size> struct BuiltinType<unsigned int , Size, 32> { typedef unsigned int type Vc_VECBUILTIN; };
110 template <size_t Size> struct BuiltinType< short , Size, 32> { typedef short type Vc_VECBUILTIN; };
111 template <size_t Size> struct BuiltinType<unsigned short , Size, 32> { typedef unsigned short type Vc_VECBUILTIN; };
112 template <size_t Size> struct BuiltinType< char , Size, 32> { typedef char type Vc_VECBUILTIN; };
113 template <size_t Size> struct BuiltinType<unsigned char , Size, 32> { typedef unsigned char type Vc_VECBUILTIN; };
114 template <size_t Size> struct BuiltinType< signed char , Size, 32> { typedef signed char type Vc_VECBUILTIN; };
115 template <size_t Size> struct BuiltinType< bool , Size, 32> { typedef unsigned char type Vc_VECBUILTIN; };
116 #undef Vc_VECBUILTIN
117 #endif
118 } // namespace Detail
119 
120 template <typename ValueType, size_t Size>
121 using IntrinsicType = typename Detail::IntrinsicType<ValueType, Size>::type;
122 
123 template <typename ValueType, size_t Size>
124 using BuiltinType = typename Detail::BuiltinType<ValueType, Size>::type;
125 
126 namespace AliasStrategy
127 {
128 struct Union {};
129 struct MayAlias {};
130 struct VectorBuiltin {};
131 struct UnionMembers {};
132 } // namespace AliasStrategy
133 
134 using DefaultStrategy =
135 #if defined Vc_USE_BUILTIN_VECTOR_TYPES
136  AliasStrategy::VectorBuiltin;
137 #elif defined Vc_MSVC
138  AliasStrategy::UnionMembers;
139 #elif defined Vc_ICC
140  AliasStrategy::Union;
141 #elif defined __GNUC__
142  AliasStrategy::MayAlias;
143 #else
144  AliasStrategy::Union;
145 #endif
146 
147 template <typename ValueType, size_t Size, typename Strategy = DefaultStrategy>
148 class Storage;
149 
150 // GCC 6 forbids `EntryType m[]` altogether
151 template <typename ValueType, size_t Size>
152 class Storage<ValueType, Size, AliasStrategy::Union>
153 {
154  static_assert(std::is_fundamental<ValueType>::value &&
155  std::is_arithmetic<ValueType>::value,
156  "Only works for fundamental arithmetic types.");
157 
158 public:
159  using VectorType = IntrinsicType<ValueType, Size>;
160  using EntryType = ValueType;
161 
162  union Alias {
163  Vc_INTRINSIC Alias(VectorType vv) : v(vv) {}
164  VectorType v;
165  EntryType m[Size];
166  };
167 
168  Vc_INTRINSIC Storage() : data(Vc::Detail::zero<VectorType>()) {}
169  Vc_INTRINSIC Storage(const VectorType &x) : data(x) { assertCorrectAlignment(&data); }
170  template <typename U>
171  Vc_INTRINSIC explicit Storage(const U &x,
172  enable_if<sizeof(U) == sizeof(VectorType)> = nullarg)
173  : data(reinterpret_cast<VectorType>(x))
174  {
175  assertCorrectAlignment(&data);
176  }
177 
178  Vc_INTRINSIC Storage(const Storage &) = default;
179  Vc_INTRINSIC Storage &operator=(const Storage &) = default;
180 
181  Vc_INTRINSIC operator const VectorType &() const { return data; }
182  Vc_INTRINSIC Vc_PURE VectorType &v() { return data; }
183  Vc_INTRINSIC Vc_PURE const VectorType &v() const { return data; }
184  Vc_INTRINSIC Vc_PURE EntryType m(size_t i) const { return Alias(data).m[i]; }
185  Vc_INTRINSIC void set(size_t i, EntryType x)
186  {
187  Alias a(data);
188  a.m[i] = x;
189  data = a.v;
190  }
191 
192 private:
193  VectorType data;
194 };
195 
196 template <typename ValueType, size_t Size>
197 class Storage<ValueType, Size, AliasStrategy::MayAlias>
198 {
199  static_assert(std::is_fundamental<ValueType>::value &&
200  std::is_arithmetic<ValueType>::value,
201  "Only works for fundamental arithmetic types.");
202 
203 public:
204  using VectorType = IntrinsicType<ValueType, Size>;
205  using EntryType = ValueType;
206 
207  Vc_INTRINSIC Storage() : data() { assertCorrectAlignment(&data); }
208  Vc_INTRINSIC Storage(const VectorType &x) : data(x)
209  {
210  assertCorrectAlignment(&data);
211  }
212  template <typename U>
213  Vc_INTRINSIC explicit Storage(const U &x,
214  enable_if<sizeof(U) == sizeof(VectorType)> = nullarg)
215  : data(reinterpret_cast<const VectorType &>(x))
216  {
217  assertCorrectAlignment(&data);
218  }
219  Vc_INTRINSIC Storage &operator=(const VectorType &x)
220  {
221  data = x;
222  return *this;
223  }
224 
225  Vc_INTRINSIC Storage(const Storage &) = default;
226  Vc_INTRINSIC Storage &operator=(const Storage &) = default;
227 
228  Vc_INTRINSIC operator const VectorType &() const { return v(); }
229  Vc_INTRINSIC Vc_PURE VectorType &v() { return data; }
230  Vc_INTRINSIC Vc_PURE const VectorType &v() const { return data; }
231 
232  Vc_INTRINSIC Vc_PURE EntryType m(size_t i) const
233  {
234  return reinterpret_cast<const MayAlias<EntryType> *>(&data)[i];
235  }
236  Vc_INTRINSIC void set(size_t i, EntryType x)
237  {
238  reinterpret_cast<MayAlias<EntryType> *>(&data)[i] = x;
239  }
240 
241 private:
242  VectorType data;
243 };
244 
245 template <typename ValueType, size_t Size>
246 class Storage<ValueType, Size, AliasStrategy::VectorBuiltin>
247 {
248  static_assert(std::is_fundamental<ValueType>::value &&
249  std::is_arithmetic<ValueType>::value,
250  "Only works for fundamental arithmetic types.");
251 
252  using Builtin = BuiltinType<ValueType, Size>;
253 
254 public:
255  using VectorType =
256 #ifdef Vc_TEMPLATES_DROP_ATTRIBUTES
257  MayAlias<IntrinsicType<ValueType, Size>>;
258 #else
259  IntrinsicType<ValueType, Size>;
260 #endif
261  using EntryType = ValueType;
262 
263  Vc_INTRINSIC Storage() : data() { assertCorrectAlignment(&data); }
264  Vc_INTRINSIC Storage(const VectorType &x)
265  : data(reinterpret_cast<const MayAlias<Builtin> &>(x))
266  {
267  assertCorrectAlignment(&data);
268  }
269  template <typename U>
270  Vc_INTRINSIC explicit Storage(const U &x,
271  enable_if<sizeof(U) == sizeof(VectorType)> = nullarg)
272  : data(reinterpret_cast<const MayAlias<Builtin> &>(x))
273  {
274  assertCorrectAlignment(&data);
275  }
276  Vc_INTRINSIC Storage &operator=(const VectorType &x)
277  {
278  data = reinterpret_cast<const MayAlias<Builtin> &>(x);
279  return *this;
280  }
281 
282  Vc_INTRINSIC Storage(const Storage &) = default;
283  Vc_INTRINSIC Storage &operator=(const Storage &) = default;
284 
285  Vc_INTRINSIC operator const VectorType &() const { return v(); }
286  Vc_INTRINSIC Vc_PURE VectorType &v() { return reinterpret_cast<VectorType &>(data); }
287  Vc_INTRINSIC Vc_PURE const VectorType &v() const { return reinterpret_cast<const VectorType &>(data); }
288 
289  Vc_INTRINSIC Vc_PURE EntryType m(size_t i) const { return data[i]; }
290  Vc_INTRINSIC void set(size_t i, EntryType x) { data[i] = x; }
291 
292  Vc_INTRINSIC Builtin &builtin() { return data; }
293  Vc_INTRINSIC const Builtin &builtin() const { return data; }
294 
295 private:
296  Builtin data;
297 };
298 
299 template <typename ValueType, size_t Size>
300 class Storage<ValueType, Size, AliasStrategy::UnionMembers>
301 {
302  static_assert(std::is_fundamental<ValueType>::value &&
303  std::is_arithmetic<ValueType>::value,
304  "Only works for fundamental arithmetic types.");
305 
306 public:
307  using VectorType = IntrinsicType<ValueType, Size>;
308  using EntryType = ValueType;
309 
310  Vc_INTRINSIC Storage() : data() { assertCorrectAlignment(&data); }
311  Vc_INTRINSIC Storage(const VectorType &x) : data(x)
312  {
313  assertCorrectAlignment(&data);
314  }
315  template <typename U>
316  Vc_INTRINSIC explicit Storage(const U &x,
317  enable_if<sizeof(U) == sizeof(VectorType)> = nullarg)
318  : data(reinterpret_cast<const VectorType &>(x))
319  {
320  assertCorrectAlignment(&data);
321  }
322  Vc_INTRINSIC Storage &operator=(const VectorType &x)
323  {
324  data = x;
325  return *this;
326  }
327 
328  Vc_INTRINSIC Storage(const Storage &) = default;
329  Vc_INTRINSIC Storage &operator=(const Storage &) = default;
330 
331  Vc_INTRINSIC Vc_PURE VectorType &v() { return data; }
332  Vc_INTRINSIC Vc_PURE const VectorType &v() const { return data; }
333 
334  Vc_INTRINSIC_L Vc_PURE_L EntryType m(size_t i) const Vc_INTRINSIC_R Vc_PURE_R;
335  Vc_INTRINSIC void set(size_t i, EntryType x) { ref(i) = x; }
336 
337 private:
338  Vc_INTRINSIC_L Vc_PURE_L EntryType &ref(size_t i) Vc_INTRINSIC_R Vc_PURE_R;
339  VectorType data;
340 };
341 
342 #ifdef Vc_MSVC
343 template <> Vc_INTRINSIC Vc_PURE double Storage< double, 2, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128d_f64[i]; }
344 template <> Vc_INTRINSIC Vc_PURE float Storage< float , 4, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128_f32[i]; }
345 template <> Vc_INTRINSIC Vc_PURE signed int Storage< signed int , 4, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_i32[i]; }
346 template <> Vc_INTRINSIC Vc_PURE signed short Storage< signed short , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_i16[i]; }
347 template <> Vc_INTRINSIC Vc_PURE signed char Storage< signed char ,16, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_i8[i]; }
348 template <> Vc_INTRINSIC Vc_PURE unsigned int Storage<unsigned int , 4, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_u32[i]; }
349 template <> Vc_INTRINSIC Vc_PURE unsigned short Storage<unsigned short , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_u16[i]; }
350 template <> Vc_INTRINSIC Vc_PURE unsigned char Storage<unsigned char ,16, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_u8[i]; }
351 
352 template <> Vc_INTRINSIC Vc_PURE double &Storage< double, 2, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128d_f64[i]; }
353 template <> Vc_INTRINSIC Vc_PURE float &Storage< float , 4, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128_f32[i]; }
354 template <> Vc_INTRINSIC Vc_PURE signed int &Storage< signed int , 4, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_i32[i]; }
355 template <> Vc_INTRINSIC Vc_PURE signed short &Storage< signed short , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_i16[i]; }
356 template <> Vc_INTRINSIC Vc_PURE signed char &Storage< signed char ,16, AliasStrategy::UnionMembers>::ref(size_t i) { return reinterpret_cast<signed char &>(data.m128i_i8[i]); }
357 template <> Vc_INTRINSIC Vc_PURE unsigned int &Storage<unsigned int , 4, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_u32[i]; }
358 template <> Vc_INTRINSIC Vc_PURE unsigned short &Storage<unsigned short , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_u16[i]; }
359 template <> Vc_INTRINSIC Vc_PURE unsigned char &Storage<unsigned char ,16, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_u8[i]; }
360 
361 #ifdef Vc_IMPL_AVX
362 template <> Vc_INTRINSIC Vc_PURE double Storage< double, 4, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256d_f64[i]; }
363 template <> Vc_INTRINSIC Vc_PURE float Storage< float , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256_f32[i]; }
364 template <> Vc_INTRINSIC Vc_PURE signed int Storage< signed int , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_i32[i]; }
365 template <> Vc_INTRINSIC Vc_PURE signed short Storage< signed short ,16, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_i16[i]; }
366 template <> Vc_INTRINSIC Vc_PURE signed char Storage< signed char ,32, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_i8[i]; }
367 template <> Vc_INTRINSIC Vc_PURE unsigned int Storage<unsigned int , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_u32[i]; }
368 template <> Vc_INTRINSIC Vc_PURE unsigned short Storage<unsigned short ,16, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_u16[i]; }
369 template <> Vc_INTRINSIC Vc_PURE unsigned char Storage<unsigned char ,32, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_u8[i]; }
370 
371 template <> Vc_INTRINSIC Vc_PURE double &Storage< double, 4, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256d_f64[i]; }
372 template <> Vc_INTRINSIC Vc_PURE float &Storage< float , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256_f32[i]; }
373 template <> Vc_INTRINSIC Vc_PURE signed int &Storage< signed int , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_i32[i]; }
374 template <> Vc_INTRINSIC Vc_PURE signed short &Storage< signed short ,16, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_i16[i]; }
375 template <> Vc_INTRINSIC Vc_PURE signed char &Storage< signed char ,32, AliasStrategy::UnionMembers>::ref(size_t i) { return reinterpret_cast<signed char &>(data.m256i_i8[i]); }
376 template <> Vc_INTRINSIC Vc_PURE unsigned int &Storage<unsigned int , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_u32[i]; }
377 template <> Vc_INTRINSIC Vc_PURE unsigned short &Storage<unsigned short ,16, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_u16[i]; }
378 template <> Vc_INTRINSIC Vc_PURE unsigned char &Storage<unsigned char ,32, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_u8[i]; }
379 #endif
380 #endif // Vc_MSVC
381 
382 template <typename VectorType, typename EntryType>
383 using VectorMemoryUnion = Storage<EntryType, sizeof(VectorType) / sizeof(EntryType)>;
384 
385 } // namespace Common
386 } // namespace Vc
387 
388 #endif // VC_COMMON_STORAGE_H_
Vector Classes Namespace.
Definition: cpuid.h:32