Vc  1.1.0
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 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the names of contributing organizations nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 }}}*/
28 
29 #ifndef VC_COMMON_STORAGE_H_
30 #define VC_COMMON_STORAGE_H_
31 
32 #include "aliasingentryhelper.h"
33 #include "types.h"
34 #include "maskentry.h"
35 #ifdef Vc_IMPL_AVX
36 #include "../avx/intrinsics.h"
37 #endif
38 #include "macros.h"
39 
40 namespace Vc_VERSIONED_NAMESPACE
41 {
42 namespace Common
43 {
44 namespace Detail
45 {
46 #ifdef Vc_IMPL_AVX
47 template <typename ValueType, size_t Size> struct IntrinsicType {
48  using type = typename std::conditional<
49  std::is_integral<ValueType>::value,
50  typename std::conditional<sizeof(ValueType) * Size == 16, __m128i, __m256i>::type,
51  typename std::conditional<
52  std::is_same<ValueType, double>::value,
53  typename std::conditional<sizeof(ValueType) * Size == 16, __m128d,
54  __m256d>::type,
55  typename std::conditional<sizeof(ValueType) * Size == 16, __m128,
56  __m256>::type>::type>::type;
57 };
58 #elif defined Vc_IMPL_SSE
59 template <typename ValueType, size_t Size> struct IntrinsicType {
60  using type = typename std::conditional<
61  std::is_integral<ValueType>::value, __m128i,
62  typename std::conditional<std::is_same<ValueType, double>::value, __m128d,
63  __m128>::type>::type;
64 };
65 #elif defined Vc_IMPL_MIC
66 template <typename ValueType, size_t Size> struct IntrinsicType {
67  using type = typename std::conditional<
68  std::is_integral<ValueType>::value, __m512i,
69  typename std::conditional<std::is_same<ValueType, double>::value, __m512d,
70  __m512>::type>::type;
71 };
72 #else
73 template <typename ValueType, size_t Size> struct IntrinsicType {
74  static_assert(Size == 1,
75  "IntrinsicType without SIMD target support may only have Size = 1");
76  using type = ValueType;
77 };
78 #endif
79 template <typename ValueType, size_t Size, size_t Bytes = sizeof(ValueType) * Size>
80 struct BuiltinType {
81  // this is required for expressions which should be substitution failures in an
82  // enable_if:
83  typedef ValueType type;
84 };
85 #ifdef Vc_USE_BUILTIN_VECTOR_TYPES
86 #define Vc_VECBUILTIN __attribute__((__vector_size__(16)))
87 template <size_t Size> struct BuiltinType< double , Size, 16> { typedef double type Vc_VECBUILTIN; };
88 template <size_t Size> struct BuiltinType< float , Size, 16> { typedef float type Vc_VECBUILTIN; };
89 template <size_t Size> struct BuiltinType< long long, Size, 16> { typedef long long type Vc_VECBUILTIN; };
90 template <size_t Size> struct BuiltinType<unsigned long long, Size, 16> { typedef unsigned long long type Vc_VECBUILTIN; };
91 template <size_t Size> struct BuiltinType< long , Size, 16> { typedef long type Vc_VECBUILTIN; };
92 template <size_t Size> struct BuiltinType<unsigned long , Size, 16> { typedef unsigned long type Vc_VECBUILTIN; };
93 template <size_t Size> struct BuiltinType< int , Size, 16> { typedef int type Vc_VECBUILTIN; };
94 template <size_t Size> struct BuiltinType<unsigned int , Size, 16> { typedef unsigned int type Vc_VECBUILTIN; };
95 template <size_t Size> struct BuiltinType< short , Size, 16> { typedef short type Vc_VECBUILTIN; };
96 template <size_t Size> struct BuiltinType<unsigned short , Size, 16> { typedef unsigned short type Vc_VECBUILTIN; };
97 template <size_t Size> struct BuiltinType< char , Size, 16> { typedef char type Vc_VECBUILTIN; };
98 template <size_t Size> struct BuiltinType<unsigned char , Size, 16> { typedef unsigned char type Vc_VECBUILTIN; };
99 template <size_t Size> struct BuiltinType< signed char , Size, 16> { typedef signed 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 #undef Vc_VECBUILTIN
116 #endif
117 } // namespace Detail
118 
119 template <typename ValueType, size_t Size>
120 using IntrinsicType = typename Detail::IntrinsicType<ValueType, Size>::type;
121 
122 template <typename ValueType, size_t Size>
123 using BuiltinType = typename Detail::BuiltinType<ValueType, Size>::type;
124 
125 namespace AliasStrategy
126 {
127 struct Union {};
128 struct MayAlias {};
129 struct VectorBuiltin {};
130 struct UnionMembers {};
131 } // namespace AliasStrategy
132 
133 using DefaultStrategy =
134 #if defined Vc_USE_BUILTIN_VECTOR_TYPES
135  AliasStrategy::VectorBuiltin;
136 #elif defined Vc_MSVC
137  AliasStrategy::UnionMembers;
138 #elif defined Vc_ICC
139  AliasStrategy::Union;
140 #elif defined __GNUC__
141  AliasStrategy::MayAlias;
142 #else
143  AliasStrategy::Union;
144 #endif
145 
146 template <typename ValueType, size_t Size, typename Strategy = DefaultStrategy>
147 class Storage;
148 
149 template <typename ValueType, size_t Size>
150 class Storage<ValueType, Size, AliasStrategy::Union>
151 {
152  static_assert(std::is_fundamental<ValueType>::value &&
153  std::is_arithmetic<ValueType>::value,
154  "Only works for fundamental arithmetic types.");
155 
156 public:
157  using VectorType = IntrinsicType<ValueType, Size>;
158  using EntryType = ValueType;
159 
160  Vc_INTRINSIC Storage() : data() { assertCorrectAlignment(&data.v); }
161  Vc_INTRINSIC Storage(const VectorType &x) : data(x)
162  {
163  assertCorrectAlignment(&data.v);
164  }
165  Vc_INTRINSIC Storage &operator=(const VectorType &x)
166  {
167  data.v = x;
168  return *this;
169  }
170 
171  Vc_INTRINSIC Storage(const Storage &) = default;
172  Vc_INTRINSIC Storage &operator=(const Storage &) = default;
173 
174  Vc_INTRINSIC Vc_PURE VectorType &v() { return data.v; }
175  Vc_INTRINSIC Vc_PURE const VectorType &v() const { return data.v; }
176 
177  Vc_INTRINSIC Vc_PURE EntryType m(size_t i) const { return data.m[i]; }
178  Vc_INTRINSIC void set(size_t i, EntryType x) { data.m[i] = x; }
179  Vc_INTRINSIC Vc_PURE EntryType &ref(size_t i) { return data.m[i]; }
180 
181 private:
182  union VectorScalarUnion {
183  Vc_INTRINSIC VectorScalarUnion() : v() {}
184  Vc_INTRINSIC VectorScalarUnion(VectorType vv) : v(vv) {}
185  VectorType v;
186 #ifdef __GNUC__
187 #pragma GCC diagnostic push
188 #pragma GCC diagnostic ignored "-Wpedantic"
189 #endif
190  EntryType m[];
191 #ifdef __GNUC__
192 #pragma GCC diagnostic pop
193 #endif
194  } data;
195 };
196 
197 template <typename ValueType, size_t Size>
198 class Storage<ValueType, Size, AliasStrategy::MayAlias>
199 {
200  static_assert(std::is_fundamental<ValueType>::value &&
201  std::is_arithmetic<ValueType>::value,
202  "Only works for fundamental arithmetic types.");
203 
204 public:
205  using VectorType = IntrinsicType<ValueType, Size>;
206  using EntryType = ValueType;
207 
208  Vc_INTRINSIC Storage() : data() { assertCorrectAlignment(&data); }
209  Vc_INTRINSIC Storage(const VectorType &x) : data(x)
210  {
211  assertCorrectAlignment(&data);
212  }
213  Vc_INTRINSIC Storage &operator=(const VectorType &x)
214  {
215  data = x;
216  return *this;
217  }
218 
219  Vc_INTRINSIC Storage(const Storage &) = default;
220  Vc_INTRINSIC Storage &operator=(const Storage &) = default;
221 
222  Vc_INTRINSIC Vc_PURE VectorType &v() { return data; }
223  Vc_INTRINSIC Vc_PURE const VectorType &v() const { return data; }
224 
225  Vc_INTRINSIC Vc_PURE EntryType m(size_t i) const
226  {
227  return reinterpret_cast<const MayAlias<EntryType> *>(&data)[i];
228  }
229  Vc_INTRINSIC void set(size_t i, EntryType x)
230  {
231  reinterpret_cast<MayAlias<EntryType> *>(&data)[i] = x;
232  }
233  Vc_INTRINSIC Vc_PURE MayAlias<EntryType> &ref(size_t i)
234  {
235  return reinterpret_cast<MayAlias<EntryType> *>(&data)[i];
236  }
237 
238 private:
239  VectorType data;
240 };
241 
242 template <typename ValueType, size_t Size>
243 class Storage<ValueType, Size, AliasStrategy::VectorBuiltin>
244 {
245  static_assert(std::is_fundamental<ValueType>::value &&
246  std::is_arithmetic<ValueType>::value,
247  "Only works for fundamental arithmetic types.");
248 
249  using Builtin = BuiltinType<ValueType, Size>;
250 
251 public:
252  using VectorType = IntrinsicType<ValueType, Size>;
253  using EntryType = ValueType;
254 
255  Vc_INTRINSIC Storage() : data() { assertCorrectAlignment(&data); }
256  Vc_INTRINSIC Storage(const VectorType &x)
257  : data(reinterpret_cast<const MayAlias<Builtin> &>(x))
258  {
259  assertCorrectAlignment(&data);
260  }
261  Vc_INTRINSIC Storage &operator=(const VectorType &x)
262  {
263  data = reinterpret_cast<const MayAlias<Builtin> &>(x);
264  return *this;
265  }
266 
267  Vc_INTRINSIC Storage(const Storage &) = default;
268  Vc_INTRINSIC Storage &operator=(const Storage &) = default;
269 
270  Vc_INTRINSIC Vc_PURE VectorType &v() { return reinterpret_cast<VectorType &>(data); }
271  Vc_INTRINSIC Vc_PURE const VectorType &v() const { return reinterpret_cast<const VectorType &>(data); }
272 
273  Vc_INTRINSIC Vc_PURE EntryType m(size_t i) const { return data[i]; }
274  Vc_INTRINSIC void set(size_t i, EntryType x) { data[i] = x; }
275  Vc_INTRINSIC Vc_PURE MayAlias<EntryType> &ref(size_t i)
276  {
277  return reinterpret_cast<MayAlias<EntryType> *>(&data)[i];
278  }
279 
280  Vc_INTRINSIC Builtin &builtin() { return data; }
281  Vc_INTRINSIC const Builtin &builtin() const { return data; }
282 
283 private:
284  Builtin data;
285 };
286 
287 template <typename ValueType, size_t Size>
288 class Storage<ValueType, Size, AliasStrategy::UnionMembers>
289 {
290  static_assert(std::is_fundamental<ValueType>::value &&
291  std::is_arithmetic<ValueType>::value,
292  "Only works for fundamental arithmetic types.");
293 
294 public:
295  using VectorType = IntrinsicType<ValueType, Size>;
296  using EntryType = ValueType;
297 
298  Vc_INTRINSIC Storage() : data() { assertCorrectAlignment(&data.v); }
299  Vc_INTRINSIC Storage(const VectorType &x) : data(x)
300  {
301  assertCorrectAlignment(&data.v);
302  }
303  Vc_INTRINSIC Storage &operator=(const VectorType &x)
304  {
305  data.v = x;
306  return *this;
307  }
308 
309  Vc_INTRINSIC Storage(const Storage &) = default;
310  Vc_INTRINSIC Storage &operator=(const Storage &) = default;
311 
312  Vc_INTRINSIC Vc_PURE VectorType &v() { return data.v; }
313  Vc_INTRINSIC Vc_PURE const VectorType &v() const { return data.v; }
314 
315  Vc_INTRINSIC_L Vc_PURE_L EntryType m(size_t i) const Vc_INTRINSIC_R Vc_PURE_R;
316  Vc_INTRINSIC_L Vc_PURE_L EntryType &ref(size_t i) Vc_INTRINSIC_R Vc_PURE_R;
317  Vc_INTRINSIC void set(size_t i, EntryType x) { ref(i) = x; }
318 
319 private:
320  VectorType data;
321 };
322 
323 #ifdef Vc_MSVC
324 template <> Vc_INTRINSIC Vc_PURE double Storage< double, 2, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128d_f64[i]; }
325 template <> Vc_INTRINSIC Vc_PURE float Storage< float , 4, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128_f32[i]; }
326 template <> Vc_INTRINSIC Vc_PURE signed int Storage< signed int , 4, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_i32[i]; }
327 template <> Vc_INTRINSIC Vc_PURE signed short Storage< signed short , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_i16[i]; }
328 template <> Vc_INTRINSIC Vc_PURE signed char Storage< signed char ,16, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_i8[i]; }
329 template <> Vc_INTRINSIC Vc_PURE unsigned int Storage<unsigned int , 4, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_u32[i]; }
330 template <> Vc_INTRINSIC Vc_PURE unsigned short Storage<unsigned short , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_u16[i]; }
331 template <> Vc_INTRINSIC Vc_PURE unsigned char Storage<unsigned char ,16, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m128i_u8[i]; }
332 
333 template <> Vc_INTRINSIC Vc_PURE double &Storage< double, 2, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128d_f64[i]; }
334 template <> Vc_INTRINSIC Vc_PURE float &Storage< float , 4, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128_f32[i]; }
335 template <> Vc_INTRINSIC Vc_PURE signed int &Storage< signed int , 4, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_i32[i]; }
336 template <> Vc_INTRINSIC Vc_PURE signed short &Storage< signed short , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_i16[i]; }
337 template <> Vc_INTRINSIC Vc_PURE signed char &Storage< signed char ,16, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_i8[i]; }
338 template <> Vc_INTRINSIC Vc_PURE unsigned int &Storage<unsigned int , 4, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_u32[i]; }
339 template <> Vc_INTRINSIC Vc_PURE unsigned short &Storage<unsigned short , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_u16[i]; }
340 template <> Vc_INTRINSIC Vc_PURE unsigned char &Storage<unsigned char ,16, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m128i_u8[i]; }
341 
342 #ifdef Vc_IMPL_AVX
343 template <> Vc_INTRINSIC Vc_PURE double Storage< double, 4, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256d_f64[i]; }
344 template <> Vc_INTRINSIC Vc_PURE float Storage< float , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256_f32[i]; }
345 template <> Vc_INTRINSIC Vc_PURE signed int Storage< signed int , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_i32[i]; }
346 template <> Vc_INTRINSIC Vc_PURE signed short Storage< signed short ,16, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_i16[i]; }
347 template <> Vc_INTRINSIC Vc_PURE signed char Storage< signed char ,32, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_i8[i]; }
348 template <> Vc_INTRINSIC Vc_PURE unsigned int Storage<unsigned int , 8, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_u32[i]; }
349 template <> Vc_INTRINSIC Vc_PURE unsigned short Storage<unsigned short ,16, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_u16[i]; }
350 template <> Vc_INTRINSIC Vc_PURE unsigned char Storage<unsigned char ,32, AliasStrategy::UnionMembers>::m(size_t i) const { return data.m256i_u8[i]; }
351 
352 template <> Vc_INTRINSIC Vc_PURE double &Storage< double, 4, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256d_f64[i]; }
353 template <> Vc_INTRINSIC Vc_PURE float &Storage< float , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256_f32[i]; }
354 template <> Vc_INTRINSIC Vc_PURE signed int &Storage< signed int , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_i32[i]; }
355 template <> Vc_INTRINSIC Vc_PURE signed short &Storage< signed short ,16, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_i16[i]; }
356 template <> Vc_INTRINSIC Vc_PURE signed char &Storage< signed char ,32, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_i8[i]; }
357 template <> Vc_INTRINSIC Vc_PURE unsigned int &Storage<unsigned int , 8, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_u32[i]; }
358 template <> Vc_INTRINSIC Vc_PURE unsigned short &Storage<unsigned short ,16, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_u16[i]; }
359 template <> Vc_INTRINSIC Vc_PURE unsigned char &Storage<unsigned char ,32, AliasStrategy::UnionMembers>::ref(size_t i) { return data.m256i_u8[i]; }
360 #endif
361 #endif // Vc_MSVC
362 
363 template <typename VectorType, typename EntryType>
364 using VectorMemoryUnion = Storage<EntryType, sizeof(VectorType) / sizeof(EntryType)>;
365 
366 } // namespace Common
367 } // namespace Vc
368 
369 #endif // VC_COMMON_STORAGE_H_