我常常被迫编写两个使用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);
}
}
还有一个问题:如何减少代码重复,因为这些功能几乎相同?
答案 0 :(得分:5)
这个问题的解决方案在这里被广泛使用(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);
}
}