对齐和未对齐加载和存储SSE向量 - 如何减少代码重复?

时间:2015-04-15 15:37:35

标签: c++ sse simd

我常常被迫编写两个使用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);
    }
}

还有一个问题:如何减少代码重复,因为这些功能几乎相同?

1 个答案:

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