1 //  vector base class
2 //
3 //  Copyright (C) 2011 Tim Blechmann
4 //
5 //  This program is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation; either version 2 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; see the file COPYING.  If not, write to
17 //  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 //  Boston, MA 02111-1307, USA.
19 
20 #ifndef VEC_BASE_HPP
21 #define VEC_BASE_HPP
22 
23 #include <cassert>
24 #include <functional>
25 #include <cstring>
26 
27 #include "../detail/math.hpp"
28 
29 #if defined(__GNUC__) && defined(NDEBUG)
30 #define always_inline inline  __attribute__((always_inline))
31 #else
32 #define always_inline inline
33 #endif
34 
35 #include "stdint.h"
36 
37 namespace nova {
38 
39 
40 /* vector base class
41  *
42  * requirements:
43  * - WrappedType is the wrapped scalar type
44  * - get_pointer(VecType) should return WrappedType*
45  * - VecSize should be the number of WrappedType elements inside a VecType
46  *
47  */
48 template <typename WrappedType,
49           typename VecType,
50           int VecSize>
51 class vec_base
52 {
53     typedef union {
54         WrappedType f[VecSize];
55         VecType vec;
56     } cast_unit;
57 
58 public:
59     static const int size = VecSize;
60     static const bool has_compare_bitmask = false;
61 
62 protected:
vec_base(void)63     vec_base (void)
64     {}
65 
66 public:
vec_base(VecType arg)67     vec_base (VecType arg):
68         data_(arg)
69     {}
70 
operator VecType(void) const71     operator VecType (void) const
72     {
73         return data_;
74     }
75 
76 public:
77     /* @{ */
78     /** io */
load(const WrappedType * src)79     void load(const WrappedType * src)
80     {
81         cast_unit u;
82         for (int i = 0; i != size; ++i)
83             u.f[i] = src[i];
84         data_ = u.vec;
85     }
86 
load_first(const WrappedType * src)87     void load_first(const WrappedType * src)
88     {
89         cast_unit u;
90         u.f[0] = *src;
91         for (int i = 1; i != size; ++i)
92             u.f[i] = 0;
93         data_ = u.vec;
94     }
95 
load_aligned(const WrappedType * data)96     void load_aligned(const WrappedType * data)
97     {
98         load(data);
99     }
100 
store(WrappedType * dest) const101     void store(WrappedType * dest) const
102     {
103         cast_unit u;
104         u.vec = data_;
105         for (int i = 0; i != size; ++i)
106             dest[i] = u.f[i];
107     }
108 
store_aligned(WrappedType * dest) const109     void store_aligned(WrappedType * dest) const
110     {
111         store(dest);
112     }
113 
store_aligned_stream(WrappedType * dest) const114     void store_aligned_stream(WrappedType * dest) const
115     {
116         store(dest);
117     }
118 
clear(void)119     void clear(void)
120     {
121         set_vec(0);
122     }
123     /* @} */
124 
125 
126     /* @{ */
127     /** element access */
get(int index) const128     WrappedType get (int index) const
129     {
130         assert(index < size);
131         cast_unit u;
132         u.vec = data_;
133         return u.f[index];
134     }
135 
set(int index,WrappedType arg)136     void set (int index, WrappedType arg)
137     {
138         cast_unit u;
139         u.vec = data_;
140         u.f[index] = arg;
141         data_ = u.vec;
142     }
143 
set_vec(WrappedType value)144     void set_vec (WrappedType value)
145     {
146         cast_unit u;
147         for (int i = 0; i != size; ++i)
148             u.f[i] = value;
149         data_ = u.vec;
150     }
151 
set_slope(WrappedType start,WrappedType slope)152     WrappedType set_slope(WrappedType start, WrappedType slope)
153     {
154         WrappedType diff = 0;
155         cast_unit u;
156 
157         for (int i = 0; i != size; ++i)
158         {
159             u.f[i] = start + diff;
160             diff += slope;
161         }
162         data_ = u.vec;
163         return diff;
164     }
165 
set_exp(WrappedType start,WrappedType curve)166     WrappedType set_exp(WrappedType start, WrappedType curve)
167     {
168         WrappedType value = start;
169         cast_unit u;
170         for (int i = 0; i != size; ++i)
171         {
172             u.f[i] = value;
173             value *= curve;
174         }
175         data_ = u.vec;
176         return value;
177     }
178     /* @} */
179 
180 private:
181     template <typename Functor>
apply_unary(VecType const & arg,Functor const & f)182     static always_inline VecType apply_unary(VecType const & arg, Functor const & f)
183     {
184         cast_unit u;
185         u.vec = arg;
186 
187         for (int i = 0; i != VecSize; ++i)
188             u.f[i] = f(u.f[i]);
189         return u.vec;
190     }
191 
192     template <typename Functor>
apply_binary(VecType const & arg1,VecType const & arg2,Functor const & f)193     static always_inline VecType apply_binary(VecType const & arg1, VecType const & arg2, Functor const & f)
194     {
195         cast_unit a1, a2, ret;
196         a1.vec = arg1;
197         a2.vec = arg2;
198 
199         for (int i = 0; i != VecSize; ++i)
200             ret.f[i] = f(a1.f[i], a2.f[i]);
201         return ret.vec;
202     }
203 
204 public:
operator +(vec_base const & rhs) const205     vec_base operator+(vec_base const & rhs) const
206     {
207         return vec_base::apply_binary(data_, rhs.data_, std::plus<WrappedType>());
208     }
209 
operator -(vec_base const & rhs) const210     vec_base operator-(vec_base const & rhs) const
211     {
212         return vec_base::apply_binary(data_, rhs.data_, std::minus<WrappedType>());
213     }
214 
operator *(vec_base const & rhs) const215     vec_base operator*(vec_base const & rhs) const
216     {
217         return vec_base::apply_binary(data_, rhs.data_, std::multiplies<WrappedType>());
218     }
219 
operator /(vec_base const & rhs) const220     vec_base operator/(vec_base const & rhs) const
221     {
222         return vec_base::apply_binary(data_, rhs.data_, std::divides<WrappedType>());
223     }
224 
operator +=(vec_base const & rhs)225     vec_base & operator+=(vec_base const & rhs)
226     {
227         data_ = vec_base::apply_binary(data_, rhs.data_, std::plus<WrappedType>());
228         return *this;
229     }
230 
operator -=(vec_base const & rhs)231     vec_base & operator-=(vec_base const & rhs)
232     {
233         data_ = vec_base::apply_binary(data_, rhs.data_, std::minus<WrappedType>());
234         return *this;
235     }
236 
operator *=(vec_base const & rhs)237     vec_base & operator*=(vec_base const & rhs)
238     {
239         data_ = vec_base::apply_binary(data_, rhs.data_, std::multiplies<WrappedType>());
240         return *this;
241     }
242 
operator /=(vec_base const & rhs)243     vec_base & operator/=(vec_base const & rhs)
244     {
245         data_ = vec_base::apply_binary(data_, rhs.data_, std::divides<WrappedType>());
246         return *this;
247     }
248 
operator <(vec_base const & rhs) const249     vec_base operator<(vec_base const & rhs) const
250     {
251         return vec_base::apply_binary(data_, rhs.data_, std::less<WrappedType>());
252     }
253 
operator <=(vec_base const & rhs) const254     vec_base operator<=(vec_base const & rhs) const
255     {
256         return vec_base::apply_binary(data_, rhs.data_, std::less_equal<WrappedType>());
257     }
258 
operator ==(vec_base const & rhs) const259     vec_base operator==(vec_base const & rhs) const
260     {
261         return vec_base::apply_binary(data_, rhs.data_, std::equal_to<WrappedType>());
262     }
263 
operator !=(vec_base const & rhs) const264     vec_base operator!=(vec_base const & rhs) const
265     {
266         return vec_base::apply_binary(data_, rhs.data_, std::not_equal_to<WrappedType>());
267     }
268 
operator >(vec_base const & rhs) const269     vec_base operator>(vec_base const & rhs) const
270     {
271         return vec_base::apply_binary(data_, rhs.data_, std::greater<WrappedType>());
272     }
273 
operator >=(vec_base const & rhs) const274     vec_base operator>=(vec_base const & rhs) const
275     {
276         return vec_base::apply_binary(data_, rhs.data_, std::greater_equal<WrappedType>());
277     }
278 
279 #define DEFINE_UNARY_STATIC(NAME, METHOD)                   \
280     static always_inline VecType NAME(VecType const & arg)  \
281     {                                                       \
282        return apply_unary(arg, METHOD<WrappedType>);        \
283     }
284 
285 #define DEFINE_BINARY_STATIC(NAME, METHOD)                                          \
286     static always_inline VecType NAME(VecType const & arg1, VecType const & arg2)   \
287     {                                                                               \
288        return apply_binary(arg1, arg2, METHOD<WrappedType>);                        \
289     }
290 
291 
292 protected:
293     DEFINE_UNARY_STATIC(reciprocal, detail::reciprocal)
294 
295     DEFINE_UNARY_STATIC(sin, detail::sin)
296     DEFINE_UNARY_STATIC(cos, detail::cos)
297     DEFINE_UNARY_STATIC(tan, detail::tan)
298 
299     DEFINE_UNARY_STATIC(asin, detail::asin)
300     DEFINE_UNARY_STATIC(acos, detail::acos)
301     DEFINE_UNARY_STATIC(atan, detail::atan)
302 
303     DEFINE_UNARY_STATIC(tanh, detail::tanh)
304 
305     DEFINE_UNARY_STATIC(log, detail::log)
306     DEFINE_UNARY_STATIC(log2, detail::log2)
307     DEFINE_UNARY_STATIC(log10, detail::log10)
308     DEFINE_UNARY_STATIC(exp, detail::exp)
309     DEFINE_UNARY_STATIC(signed_sqrt, detail::signed_sqrt)
310 
311     DEFINE_UNARY_STATIC(round, detail::round)
312     DEFINE_UNARY_STATIC(ceil, detail::ceil)
313     DEFINE_UNARY_STATIC(floor, detail::floor)
314     DEFINE_UNARY_STATIC(frac, detail::frac)
315     DEFINE_UNARY_STATIC(trunc, detail::trunc)
316 
317     DEFINE_BINARY_STATIC(pow, detail::pow)
318     DEFINE_BINARY_STATIC(signed_pow, detail::signed_pow)
319 
320     DEFINE_UNARY_STATIC(abs, detail::fabs)
321     DEFINE_UNARY_STATIC(sign, detail::sign)
322     DEFINE_UNARY_STATIC(square, detail::square)
323     DEFINE_UNARY_STATIC(cube, detail::cube)
324 
325     DEFINE_BINARY_STATIC(max_, detail::max)
326     DEFINE_BINARY_STATIC(min_, detail::min)
327 
328     DEFINE_UNARY_STATIC(undenormalize, detail::undenormalize)
329 
330 public:
horizontal_min(void) const331     WrappedType horizontal_min(void) const
332     {
333         cast_unit u;
334         u.vec = data_;
335         return *std::min_element(u.f, u.f + size);
336     }
337 
horizontal_max(void) const338     WrappedType horizontal_max(void) const
339     {
340         cast_unit u;
341         u.vec = data_;
342         return *std::max_element(u.f, u.f + size);
343     }
344 
horizontal_sum(void) const345     WrappedType horizontal_sum(void) const
346     {
347         cast_unit u;
348         u.vec = data_;
349         WrappedType ret = 0;
350         for (int i = 0; i != size; ++i)
351             ret += u.f[i];
352         return ret;
353     }
354 
355     template <typename Functor>
collect(Functor const & f)356     VecType collect(Functor const & f)
357     {
358         vec_base ret;
359         for (int i = 0; i != size; ++i)
360             ret.set(i, f(get(i)));
361         return ret.data_;
362     }
363 
364 protected:
365     VecType data_;
366 };
367 
368 }
369 
370 #define NOVA_SIMD_DELEGATE_UNARY_TO_BASE(NAME)  \
371     inline friend vec NAME(vec const & arg)     \
372     {                                           \
373         return base::NAME(arg.data_);            \
374     }
375 
376 #define NOVA_SIMD_DELEGATE_OPERATOR_TO_BASE(NAME)  \
377     inline vec NAME(vec const & rhs) const         \
378     {                                              \
379         return base::NAME(rhs.data_);               \
380     }
381 
382 #define NOVA_SIMD_DELEGATE_BINARY_TO_BASE(NAME)                 \
383     inline friend vec NAME(vec const & arg1, vec const & arg2)  \
384     {                                                           \
385         return base::NAME(arg1.data_, arg2.data_);               \
386     }
387 
388 #define NOVA_SIMD_DEFINE_MADD                                   \
389     inline friend vec madd(vec const & arg1, vec const & arg2, vec const & arg3)  \
390     {                                                           \
391         return arg1 * arg2 + arg3;                       \
392     }
393 
394 #undef always_inline
395 
396 
397 #endif /* VEC_BASE_HPP */
398