SSE运算符+ =用于向量

时间:2013-02-27 22:07:48

标签: c performance vector sse

我有两个double类型的数组,我想执行vecA += vecB。到目前为止,我正在做vecA = vecA + vecB据我所知,例如写i = i + 5的整数比i += 5慢。所以我想知道,是否有一些SSE功能只能在__m128d上进行operator+=。我搜查了一下,一无所获。我的应用程序花费大约60%的时间用于此vecA = vecA + vecB操作,因此将显示任何性能提升。

下面代码片段中的所有数组均为16字节对齐,len始终为偶数。

原始代码只是

inline void addToDoubleVectorSSE(
         const double * what, const double * toWhat, double * dest, const unsigned int len)
{
   __m128d * _what      = (__m128d*)what;
   __m128d * _toWhat    = (__m128d*)toWhat;

   for ( register unsigned int i = 0; i < len; i+= 2 )
   {
       *_toWhat = _mm_add_pd( *_what, *_toWhat );
       _what++;
       _toWhat++;
   }
}

在阅读http://fastcpp.blogspot.cz/2011/04/how-to-process-stl-vector-using-sse.html之后,作者通过不立即写入他刚读的内容来获得表现,我试过了

__m128d * _what         = (__m128d*)what;
__m128d * _toWhat       = (__m128d*)toWhat;
__m128d * _toWhatBase   = (__m128d*)toWhat;

__m128d _dest1;
__m128d _dest2;

for ( register unsigned int i = 0; i < len; i+= 4 )
{
    _toWhatBase = _toWhat;
    _dest1      = _mm_add_pd( *_what++, *_toWhat++ );
    _dest2      = _mm_add_pd( *_what++, *_toWhat++ );

    *_toWhatBase++ = _dest1;
    *_toWhatBase++ = _dest2;
}

但速度方面没有改善。那么operator+=是否有__m128d?或者是否有其他方法可以用于在双精度数组上执行operator + =?使用MSVC,目标平台在Intel i7 CPU上始终是Windows(XP和7)。

2 个答案:

答案 0 :(得分:4)

您正在做不必要的工作,现代编译器会自动生成这种代码。该功能称为“自动矢量化”。 MSVC在VS2012中也支持它。我无法理解你的代码,所以我重写了这样:

inline void addToDoubleVectorSSE(
         const double * what, double * toWhat, const unsigned int len)
{
    for (unsigned ix = 0; ix < len; ++ix) 
        toWhat[ix] += what[ix];
}

哪个产生了这个机器代码:

00A3102E  xor         eax,eax  
00A31030  movupd      xmm0,xmmword ptr [esp+eax+358h]  
00A31039  movupd      xmm1,xmmword ptr [esp+eax+38h]  
00A3103F  add         eax,10h  
00A31042  addpd       xmm1,xmm0                          // <=== Look!!
00A31046  movupd      xmmword ptr [esp+eax+348h],xmm1  
00A3104F  cmp         eax,320h  
00A31054  jb          wmain+30h (0A31030h) 

显然,鉴于代码看起来更干净,你应该支持这个解决方案。如有必要,请更新您的VS版本。

答案 1 :(得分:3)

据我所知,没有等效的+=,因为SSE算术运算通常是寄存器到寄存器或存储器到寄存器,但不是寄存器到存储器。

但是,您可以使用您链接的博客文章中的建议来改善您的表现。诀窍无法为您效果的原因是您没有消除两条指令之间的依赖关系:++_what++_toWhat++增量的副作用会阻止第二对从同一时间开始的操作。按如下方式修改循环以获得改进:

for ( register unsigned int i = 0; i < len; i+= 4, _what += 2, _toWhat += 2, _toWhatBase+=2 )
{
    _toWhatBase = _toWhat;
    _dest1      = _mm_add_pd( *_what, *_toWhat );
    _dest2      = _mm_add_pd( *(_what+1), *(_toWhat+1));

    *_toWhatBase = _dest1;
    *(_toWhatBase+1) = _dest2;
}

更改后,_dest2上的操作独立于_dest1上的操作

根据我的挂钟估计,经过这个简单的修改,我得到了大约28%的改善。