Nektar++
scalar.hpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: scalar.hpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Scalar type used when a vector type is needed, but no SIMD
32 // extension is available.
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 #ifndef NEKTAR_LIB_LIBUTILITES_SIMDLIB_SCALAR_H
37 #define NEKTAR_LIB_LIBUTILITES_SIMDLIB_SCALAR_H
38 
39 #include "allocator.hpp"
40 #include "traits.hpp"
41 #include <cmath>
42 #include <cstdint>
43 #include <type_traits>
44 #include <vector>
45 
46 namespace tinysimd
47 {
48 
49 namespace abi
50 {
51 
52 template <typename scalarType> struct scalar
53 {
54  using type = void;
55 };
56 
57 } // namespace abi
58 
59 // forward declaration of concrete types
60 // makes default type available for all arithmetic types
61 template <typename T,
62  typename =
63  typename std::enable_if<std::is_arithmetic<T>::value>::type>
64 struct scalarT;
65 struct scalarMask;
66 
67 namespace abi
68 {
69 
70 // mapping between abstract types and concrete types
71 template <> struct scalar<double>
72 {
74 };
75 template <> struct scalar<float>
76 {
78 };
79 template <> struct scalar<std::int64_t>
80 {
82 };
83 template <> struct scalar<std::uint64_t>
84 {
86 };
87 template <> struct scalar<std::int32_t>
88 {
90 };
91 template <> struct scalar<std::uint32_t>
92 {
94 };
95 template <> struct scalar<bool>
96 {
97  using type = scalarMask;
98 };
99 
100 #ifdef __APPLE__ // for apple size_t is recognised as uint64_t
101 template <> struct scalar<size_t>
102 {
103  using type = scalarT<size_t>;
104 };
105 #endif
106 
107 } // namespace abi
108 
109 // concrete types
110 template <typename T, typename> struct scalarT
111 {
112  static constexpr unsigned int width = 1;
113  static constexpr unsigned int alignment = sizeof(T);
114 
115  using scalarType = T;
118 
119  // storage
121 
122  // ctors
123  inline scalarT() = default;
124  inline scalarT(const scalarT &rhs) = default;
125  inline scalarT(const vectorType &rhs) : _data(rhs)
126  {
127  }
128 
129  // copy assignment
130  inline scalarT &operator=(const scalarT &) = default;
131 
132  // store
133  inline void store(scalarType *p) const
134  {
135  *p = _data;
136  }
137 
138  template <class flag> inline void store(scalarType *p, flag) const
139  {
140  *p = _data;
141  }
142 
143  // load
144  inline void load(const scalarType *p)
145  {
146  _data = *p;
147  }
148 
149  template <class flag> inline void load(const scalarType *p, flag)
150  {
151  _data = *p;
152  }
153 
154  inline void broadcast(const scalarType rhs)
155  {
156  _data = rhs;
157  }
158 
159  template <typename U, typename = typename std::enable_if<
160  std::is_integral<U>::value>::type>
161  inline void gather(const scalarType *p, const scalarT<U> &indices)
162  {
163  _data = *(p + indices._data);
164  }
165 
166  template <typename U, typename = typename std::enable_if<
167  std::is_integral<U>::value>::type>
168  inline void scatter(scalarType *p, const scalarT<U> &indices) const
169  {
170  p += indices._data;
171  *p = _data;
172  }
173 
174  // fma
175  // this = this + a * b
176  inline void fma(const scalarT<T> &a, const scalarT<T> &b)
177  {
178  _data += a._data * b._data;
179  }
180 
181  // subscript
182  inline scalarType operator[](size_t) const
183  {
184  return _data;
185  }
186 
187  inline scalarType &operator[](size_t)
188  {
189  return _data;
190  }
191 
192  // unary ops
193  inline void operator+=(scalarT<T> rhs)
194  {
195  _data += rhs._data;
196  }
197 
198  inline void operator-=(scalarT<T> rhs)
199  {
200  _data -= rhs._data;
201  }
202 
203  inline void operator*=(scalarT<T> rhs)
204  {
205  _data *= rhs._data;
206  }
207 
208  inline void operator/=(scalarT<T> rhs)
209  {
210  _data /= rhs._data;
211  }
212 };
213 
214 template <typename T>
216 {
217  return lhs._data + rhs._data;
218 }
219 template <
220  typename T, typename U,
221  typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
222 inline scalarT<T> operator+(U lhs, scalarT<T> rhs)
223 {
224  return lhs + rhs._data;
225 }
226 template <
227  typename T, typename U,
228  typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
229 inline scalarT<T> operator+(scalarT<T> lhs, U rhs)
230 {
231  return lhs._data + rhs;
232 }
233 
234 template <typename T>
236 {
237  return lhs._data - rhs._data;
238 }
239 template <
240  typename T, typename U,
241  typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
242 inline scalarT<T> operator-(U lhs, scalarT<T> rhs)
243 {
244  return lhs - rhs._data;
245 }
246 template <
247  typename T, typename U,
248  typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
249 inline scalarT<T> operator-(scalarT<T> lhs, U rhs)
250 {
251  return lhs._data - rhs;
252 }
253 
254 template <typename T>
256 {
257  return lhs._data * rhs._data;
258 }
259 template <
260  typename T, typename U,
261  typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
262 inline scalarT<T> operator*(U lhs, scalarT<T> rhs)
263 {
264  return lhs * rhs._data;
265 }
266 template <
267  typename T, typename U,
268  typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
269 inline scalarT<T> operator*(scalarT<T> lhs, U rhs)
270 {
271  return lhs._data * rhs;
272 }
273 
274 template <typename T>
276 {
277  return lhs._data / rhs._data;
278 }
279 template <
280  typename T, typename U,
281  typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
282 inline scalarT<T> operator/(U lhs, scalarT<T> rhs)
283 {
284  return lhs / rhs._data;
285 }
286 template <
287  typename T, typename U,
288  typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
289 inline scalarT<T> operator/(scalarT<T> lhs, U rhs)
290 {
291  return lhs._data / rhs;
292 }
293 
294 template <typename T> inline scalarT<T> sqrt(scalarT<T> in)
295 {
296  return std::sqrt(in._data);
297 }
298 template <typename T> inline scalarT<T> abs(scalarT<T> in)
299 {
300  return std::abs(in._data);
301 }
302 
303 template <typename T> inline scalarT<T> log(scalarT<T> in)
304 {
305  return std::log(in._data);
306 }
307 
308 template <typename T>
309 inline void load_interleave(const T *in, size_t dataLen,
310  std::vector<scalarT<T>, allocator<scalarT<T>>> &out)
311 {
312  for (size_t i = 0; i < dataLen; ++i)
313  {
314  out[i] = in[i];
315  }
316 }
317 
318 template <typename T>
319 inline void deinterleave_store(
320  const std::vector<scalarT<T>, allocator<scalarT<T>>> &in, size_t dataLen,
321  T *out)
322 {
323  for (size_t i = 0; i < dataLen; ++i)
324  {
325  out[i] = in[i]._data;
326  }
327 }
328 
329 ////////////////////////////////////////////////////////////////////////////////
330 
331 // mask type
332 // mask is a int type that uses boolean promotion
333 //
334 // VERY LIMITED SUPPORT...just enough to make cubic eos work...
335 //
336 struct scalarMask : public scalarT<std::uint64_t>
337 {
338  // bring in ctors
339  using scalarT::scalarT;
340 
341  static constexpr scalarType true_v = true;
342  static constexpr scalarType false_v = false;
343 
344  // needs to be able to work with std::uint32_t
345  // for single precision overload
346  // usually using 32 or 64 bits would result in a different number of lanes
347  // this is not the case for a scalar
348 
349  // store
350  inline void store(std::uint32_t *p) const
351  {
352  *p = static_cast<std::uint32_t>(_data);
353  }
354 
355  // load
356  inline void load(const std::uint32_t *p)
357  {
358  _data = static_cast<std::uint32_t>(*p);
359  }
360 
361  // make base implementations visible
364 };
365 
367 {
368  return lhs._data > rhs._data;
369 }
370 
372 {
373  return lhs._data > rhs._data;
374 }
375 
376 inline bool operator&&(scalarMask lhs, bool rhs)
377 {
378  return lhs._data && rhs;
379 }
380 
381 } // namespace tinysimd
382 #endif
scalarT< T > log(scalarT< T > in)
Definition: scalar.hpp:303
scalarT< T > operator+(scalarT< T > lhs, scalarT< T > rhs)
Definition: scalar.hpp:215
void deinterleave_store(const std::vector< scalarT< T >, allocator< scalarT< T >>> &in, size_t dataLen, T *out)
Definition: scalar.hpp:319
scalarT< T > operator-(scalarT< T > lhs, scalarT< T > rhs)
Definition: scalar.hpp:235
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:298
boost::alignment::aligned_allocator< T, T::alignment > allocator
Definition: allocator.hpp:49
scalarMask operator>(scalarT< double > lhs, scalarT< double > rhs)
Definition: scalar.hpp:366
void load_interleave(const T *in, size_t dataLen, std::vector< scalarT< T >, allocator< scalarT< T >>> &out)
Definition: scalar.hpp:309
bool operator&&(scalarMask lhs, bool rhs)
Definition: scalar.hpp:376
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294
scalarT< T > operator/(scalarT< T > lhs, scalarT< T > rhs)
Definition: scalar.hpp:275
scalarT< T > operator*(scalarT< T > lhs, scalarT< T > rhs)
Definition: scalar.hpp:255
static constexpr scalarType false_v
Definition: scalar.hpp:342
void load(const std::uint32_t *p)
Definition: scalar.hpp:356
void store(std::uint32_t *p) const
Definition: scalar.hpp:350
static constexpr scalarType true_v
Definition: scalar.hpp:341
void store(scalarType *p) const
Definition: scalar.hpp:133
scalarT(const scalarT &rhs)=default
void gather(const scalarType *p, const scalarT< U > &indices)
Definition: scalar.hpp:161
vectorType _data
Definition: scalar.hpp:120
static constexpr unsigned int alignment
Definition: scalar.hpp:113
void broadcast(const scalarType rhs)
Definition: scalar.hpp:154
scalarType & operator[](size_t)
Definition: scalar.hpp:187
scalarType operator[](size_t) const
Definition: scalar.hpp:182
void operator/=(scalarT< T > rhs)
Definition: scalar.hpp:208
scalarType[width] scalarArray
Definition: scalar.hpp:117
void load(const scalarType *p, flag)
Definition: scalar.hpp:149
void operator+=(scalarT< T > rhs)
Definition: scalar.hpp:193
scalarT & operator=(const scalarT &)=default
scalarT(const vectorType &rhs)
Definition: scalar.hpp:125
static constexpr unsigned int width
Definition: scalar.hpp:112
scalarType vectorType
Definition: scalar.hpp:116
void fma(const scalarT< T > &a, const scalarT< T > &b)
Definition: scalar.hpp:176
void operator-=(scalarT< T > rhs)
Definition: scalar.hpp:198
void load(const scalarType *p)
Definition: scalar.hpp:144
void operator*=(scalarT< T > rhs)
Definition: scalar.hpp:203
void store(scalarType *p, flag) const
Definition: scalar.hpp:138
void scatter(scalarType *p, const scalarT< U > &indices) const
Definition: scalar.hpp:168