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);
    }
}