1 | #ifndef BZ_SIMDTYPES_H |
---|
2 | #define BZ_SIMDTYPES_H |
---|
3 | |
---|
4 | #include <blitz/blitz.h> |
---|
5 | #include <stdint.h> |
---|
6 | |
---|
7 | BZ_NAMESPACE(blitz) |
---|
8 | |
---|
9 | template<class T,int N> class TinyVector; |
---|
10 | |
---|
11 | /** This metaprogram returns the number of bits necessary to fit the |
---|
12 | specified number. The metaprogram result for I is obtained as |
---|
13 | _bz_meta_bitwidth<I,0>::width. */ |
---|
14 | template<size_t I, size_t L> struct _bz_meta_bitwidth { |
---|
15 | static const size_t width = _bz_meta_bitwidth<(I>>1), L+1>::width; |
---|
16 | }; |
---|
17 | |
---|
18 | template<size_t L> struct _bz_meta_bitwidth<0,L> { |
---|
19 | static const size_t width = L; |
---|
20 | }; |
---|
21 | |
---|
22 | |
---|
23 | /** Helper class that defines the width of the simd instructions for a |
---|
24 | given type. It also defines a type that is a TinyVector of the |
---|
25 | appropriate length to fill the simd width. This is used as the |
---|
26 | "evaluation type" to facilitate automatic vectorization. Because |
---|
27 | TinyVectors are aligned on BZ_SIMD_WIDTH, an array of vecType will |
---|
28 | be dense in memory, which is required to reinterpret an array of T |
---|
29 | to an array of vecType. \todo How do we check that the type fits |
---|
30 | evenly into the simd width? */ |
---|
31 | template<typename T> class simdTypes { |
---|
32 | public: |
---|
33 | /// SIMD width of type in bytes (sizeof(T) if simd width does not |
---|
34 | /// fit a T) |
---|
35 | static const size_t byteWidth = |
---|
36 | BZ_SIMD_WIDTH>sizeof(T) ? BZ_SIMD_WIDTH : sizeof(T); |
---|
37 | |
---|
38 | /// SIMD width of types in number of elements. |
---|
39 | static const size_t vecWidth = |
---|
40 | BZ_SIMD_WIDTH>sizeof(T) ? BZ_SIMD_WIDTH/sizeof(T) : 1; |
---|
41 | |
---|
42 | /// TinyVector type of T that fills the simd width. |
---|
43 | typedef TinyVector<T, vecWidth> vecType; |
---|
44 | |
---|
45 | /** Test if a pointer to T is simd aligned. */ |
---|
46 | static inline bool isVectorAligned(const T* restrict pointer) |
---|
47 | { return (uintptr_t)((void*)pointer) % BZ_SIMD_WIDTH == 0; } |
---|
48 | |
---|
49 | /** Return number of elements from pointer to next simd width |
---|
50 | boundary. This is used to figure out how many scalar operations |
---|
51 | need to be done before beginning vectorized operations. */ |
---|
52 | static inline diffType offsetToAlignment(const T* restrict pointer) { |
---|
53 | const uintptr_t m = (uintptr_t)((void*)pointer) & (byteWidth-1); |
---|
54 | return m ? (byteWidth - m)/sizeof(T) : 0; |
---|
55 | } |
---|
56 | |
---|
57 | /** Return a length which has been padded to next larger even SIMD |
---|
58 | width. */ |
---|
59 | static inline size_t paddedLength(size_t length) { |
---|
60 | return (length & (vecWidth-1)) ? |
---|
61 | (length & ~(vecWidth-1)) + vecWidth : length; |
---|
62 | }; |
---|
63 | }; |
---|
64 | |
---|
65 | /** General function just forwards to the simdTypes class. */ |
---|
66 | template <typename T> |
---|
67 | inline bool isVectorAligned(const T* restrict pointer) { |
---|
68 | return simdTypes<T>::isVectorAligned(pointer); } |
---|
69 | |
---|
70 | |
---|
71 | BZ_NAMESPACE_END |
---|
72 | |
---|
73 | #endif |
---|