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