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