SSE 向量的对齐和未对齐加载和存储 - 如何减少代码重复?
Aligned and unaligned loading and storing of SSE vectors - how to reduce code duplication?
我经常被迫编写两个使用 SSE 指令的函数实现,因为输入和输出缓冲区可能对齐或不对齐地址:
void some_function_aligned(const float * src, size_t size, float * dst)
{
for(size_t i = 0; i < size; i += 4)
{
__m128 a = _mm_load_ps(src + i);
// do something...
_mm_store_ps(dst + i, a);
}
}
和
void some_function_unaligned(const float * src, size_t size, float * dst)
{
for(size_t i = 0; i < size; i += 4)
{
__m128 a = _mm_loadu_ps(src + i);
// do something...
_mm_storeu_ps(dst + i, a);
}
}
还有一个问题:如何减少代码重复,因为这些功能几乎相等?
这里有一个广泛使用的解决这个问题的方法 (http://simd.sourceforge.net/)。
它基于用于加载和保存 SSE 向量的模板函数的特殊化:
template <bool align> __m128 load(const float * p);
template <> inline __m128 load<false>(const float * p)
{
return _mm_loadu_ps(p);
}
template <> inline __m128 load<true>(const float * p)
{
return _mm_load_ps(p);
}
template <bool align> void store(float * p, __m128 a);
template <> inline void Store<false>(float * p, __m128 a)
{
_mm_storeu_ps(p, a);
}
template <> inline void Store<true>(float * p, __m128 a)
{
_mm_store_ps(p, a);
}
现在我们只能写一个模板函数的实现:
template <bool align> void some_function(const float * src, size_t size, float * dst)
{
for(size_t i = 0; i < size; i += 4)
{
__m128 a = load<align>(src + i);
// do something...
store<align>(dst + i, a);
}
}
我经常被迫编写两个使用 SSE 指令的函数实现,因为输入和输出缓冲区可能对齐或不对齐地址:
void some_function_aligned(const float * src, size_t size, float * dst)
{
for(size_t i = 0; i < size; i += 4)
{
__m128 a = _mm_load_ps(src + i);
// do something...
_mm_store_ps(dst + i, a);
}
}
和
void some_function_unaligned(const float * src, size_t size, float * dst)
{
for(size_t i = 0; i < size; i += 4)
{
__m128 a = _mm_loadu_ps(src + i);
// do something...
_mm_storeu_ps(dst + i, a);
}
}
还有一个问题:如何减少代码重复,因为这些功能几乎相等?
这里有一个广泛使用的解决这个问题的方法 (http://simd.sourceforge.net/)。 它基于用于加载和保存 SSE 向量的模板函数的特殊化:
template <bool align> __m128 load(const float * p);
template <> inline __m128 load<false>(const float * p)
{
return _mm_loadu_ps(p);
}
template <> inline __m128 load<true>(const float * p)
{
return _mm_load_ps(p);
}
template <bool align> void store(float * p, __m128 a);
template <> inline void Store<false>(float * p, __m128 a)
{
_mm_storeu_ps(p, a);
}
template <> inline void Store<true>(float * p, __m128 a)
{
_mm_store_ps(p, a);
}
现在我们只能写一个模板函数的实现:
template <bool align> void some_function(const float * src, size_t size, float * dst)
{
for(size_t i = 0; i < size; i += 4)
{
__m128 a = load<align>(src + i);
// do something...
store<align>(dst + i, a);
}
}