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
46namespace tinysimd
47{
48
49namespace abi
50{
51
52template <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
61template <typename T,
62 typename =
63 typename std::enable_if<std::is_arithmetic<T>::value>::type>
64struct scalarT;
65struct scalarMask;
66
67namespace abi
68{
69
70// mapping between abstract types and concrete types
71template <> struct scalar<double>
72{
74};
75template <> struct scalar<float>
76{
78};
79template <> struct scalar<std::int64_t>
80{
82};
83template <> struct scalar<std::uint64_t>
84{
86};
87template <> struct scalar<std::int32_t>
88{
90};
91template <> struct scalar<std::uint32_t>
92{
94};
95template <> struct scalar<bool>
96{
98};
99
100#ifdef __APPLE__ // for apple size_t is recognised as uint64_t
101template <> struct scalar<size_t>
102{
103 using type = scalarT<size_t>;
104};
105#endif
106
107} // namespace abi
108
109// concrete types
110template <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
214template <typename T>
216{
217 return lhs._data + rhs._data;
218}
219template <
220 typename T, typename U,
221 typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
223{
224 return lhs + rhs._data;
225}
226template <
227 typename T, typename U,
228 typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
230{
231 return lhs._data + rhs;
232}
233
234template <typename T>
236{
237 return lhs._data - rhs._data;
238}
239template <
240 typename T, typename U,
241 typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
243{
244 return lhs - rhs._data;
245}
246template <
247 typename T, typename U,
248 typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
250{
251 return lhs._data - rhs;
252}
253
254template <typename T>
256{
257 return lhs._data * rhs._data;
258}
259template <
260 typename T, typename U,
261 typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
263{
264 return lhs * rhs._data;
265}
266template <
267 typename T, typename U,
268 typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
270{
271 return lhs._data * rhs;
272}
273
274template <typename T>
276{
277 return lhs._data / rhs._data;
278}
279template <
280 typename T, typename U,
281 typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
283{
284 return lhs / rhs._data;
285}
286template <
287 typename T, typename U,
288 typename = typename std::enable_if<std::is_arithmetic<U>::value>::type>
290{
291 return lhs._data / rhs;
292}
293
294template <typename T> inline scalarT<T> sqrt(scalarT<T> in)
295{
296 return std::sqrt(in._data);
297}
298template <typename T> inline scalarT<T> abs(scalarT<T> in)
299{
300 return std::abs(in._data);
301}
302
303template <typename T> inline scalarT<T> log(scalarT<T> in)
304{
305 return std::log(in._data);
306}
307
308template <typename T>
310 const T *in, const size_t dataLen,
311 std::vector<scalarT<T>, allocator<scalarT<T>>> &out)
312{
313 for (size_t i = 0; i < dataLen; ++i)
314 {
315 out[i] = in[i];
316 }
317}
318
319template <typename T>
320inline void load_interleave(const T *in, const size_t dataLen,
321 std::vector<scalarT<T>, allocator<scalarT<T>>> &out)
322{
323 for (size_t i = 0; i < dataLen; ++i)
324 {
325 out[i] = in[i];
326 }
327}
328
329template <typename T>
331 const std::vector<scalarT<T>, allocator<scalarT<T>>> &in,
332 const size_t dataLen, T *out)
333{
334 for (size_t i = 0; i < dataLen; ++i)
335 {
336 out[i] = in[i]._data;
337 }
338}
339
340template <typename T>
342 const std::vector<scalarT<T>, allocator<scalarT<T>>> &in,
343 const size_t dataLen, T *out)
344{
345 for (size_t i = 0; i < dataLen; ++i)
346 {
347 out[i] = in[i]._data;
348 }
349}
350
351////////////////////////////////////////////////////////////////////////////////
352
353// mask type
354// mask is a int type that uses boolean promotion
355//
356// VERY LIMITED SUPPORT...just enough to make cubic eos work...
357//
358struct scalarMask : public scalarT<std::uint64_t>
359{
360 // bring in ctors
361 using scalarT::scalarT;
362
363 static constexpr scalarType true_v = true;
364 static constexpr scalarType false_v = false;
365
366 // needs to be able to work with std::uint32_t
367 // for single precision overload
368 // usually using 32 or 64 bits would result in a different number of lanes
369 // this is not the case for a scalar
370
371 // store
372 inline void store(std::uint32_t *p) const
373 {
374 *p = static_cast<std::uint32_t>(_data);
375 }
376
377 // load
378 inline void load(const std::uint32_t *p)
379 {
380 _data = static_cast<std::uint32_t>(*p);
381 }
382
383 // make base implementations visible
384 using scalarT<std::uint64_t>::store;
385 using scalarT<std::uint64_t>::load;
386};
387
389{
390 return lhs._data > rhs._data;
391}
392
394{
395 return lhs._data > rhs._data;
396}
397
398inline bool operator&&(scalarMask lhs, bool rhs)
399{
400 return lhs._data && rhs;
401}
402
403} // namespace tinysimd
404#endif
STL namespace.
void load_interleave(const T *in, const size_t dataLen, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
Definition: scalar.hpp:320
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:298
void deinterleave_unalign_store(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, const size_t dataLen, T *out)
Definition: scalar.hpp:330
scalarT< T > operator-(scalarT< T > lhs, scalarT< T > rhs)
Definition: scalar.hpp:235
scalarT< T > operator/(scalarT< T > lhs, scalarT< T > rhs)
Definition: scalar.hpp:275
boost::alignment::aligned_allocator< T, T::alignment > allocator
Definition: allocator.hpp:49
scalarT< T > log(scalarT< T > in)
Definition: scalar.hpp:303
scalarT< T > operator*(scalarT< T > lhs, scalarT< T > rhs)
Definition: scalar.hpp:255
scalarMask operator>(scalarT< double > lhs, scalarT< double > rhs)
Definition: scalar.hpp:388
bool operator&&(scalarMask lhs, bool rhs)
Definition: scalar.hpp:398
void load_unalign_interleave(const T *in, const size_t dataLen, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
Definition: scalar.hpp:309
void deinterleave_store(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, const size_t dataLen, T *out)
Definition: scalar.hpp:341
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294
scalarT< T > operator+(scalarT< T > lhs, scalarT< T > rhs)
Definition: scalar.hpp:215
static constexpr scalarType false_v
Definition: scalar.hpp:364
void load(const std::uint32_t *p)
Definition: scalar.hpp:378
void store(std::uint32_t *p) const
Definition: scalar.hpp:372
static constexpr scalarType true_v
Definition: scalar.hpp:363
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) 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
scalarType & operator[](size_t)
Definition: scalar.hpp:187
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
scalarT & operator=(const scalarT &)=default
void scatter(scalarType *p, const scalarT< U > &indices) const
Definition: scalar.hpp:168