为什么movlps和movhps SSE指令比用于传输未对齐数据的movup更快?

Sea*_*tar 4 optimization assembly sse

我发现在用于进行数学计算的一些SSE优化代码中,它们使用movlps和movhps指令的组合而不是单个movups指令来传输未对齐的数据.我不知道为什么,所以我自己尝试了,这是下面的伪代码:

struct Vec4
{
    float f[4];
};

const size_t nSize = sizeof(Vec4) * 100;
Vec4* pA = (Vec4*)malloc( nSize );
Vec4* pB = (Vec4*)malloc( nSize );
Vec4* pR = (Vec4*)malloc( nSize );

...Some data initialization code here
...Records current time by QueryPerformanceCounter()

for( int i=0; i<100000, ++i )
{
    for( int j=0; j<100; ++j )
    {
          Vec4* a = &pA[i];
          Vec4* b = &pB[i];
          Vec4* r = &pR[i];
          __asm
          {
              mov eax, a
              mov ecx, b
              mov edx, r

              ...option 1:

              movups xmm0, [eax]
              movups xmm1, [ecx]
              mulps xmm0, xmm1
              movups [edx], xmm0

              ...option 2:

              movlps xmm0, [eax]
              movhps xmm0, [eax+8]
              movlps xmm1, [ecx]
              movhps xmm1, [ecx+8]
              mulps xmm0, xmm1
              movlps [edx], xmm0
              movhps [edx+8], xmm0
         }
    }
}

...Calculates passed time

free( pA );
free( pB );
free( pR );
Run Code Online (Sandbox Code Playgroud)

我运行了很多次代码并计算了他们的平均时间.

对于movups版本,结果大约是50ms.

对于movlps,movhps版本,结果大约是46ms.

我还尝试在结构上使用__declspec(align(16))描述符的数据对齐版本,并由_aligned_malloc()分配,结果大约为34ms.

为什么movlps和movhps的组合更快?这是否意味着我们最好使用movlps和movhps而不是movups?

Gun*_*iez 5

这一代(K8)的Athlons只有64位宽的ALU单元.因此,每个128位SSE指令需要分成两个64位指令,这会导致某些指令的开销.

在这种类型的处理器上,与相同的MMX代码相比,您通常不会发现使用SSE的加速.

Intel,AMD和VIA CPU的微体系结构中引用Agner Fog :汇编程序员和编译器制造商的优化指南:

12.9 64位与128位指令

在K10上使用128位指令是一个很大的优势,但在K8上则没有,因为每个128位指令在K8上被分成两个64位宏操作.

128位存储器写入指令在K10上作为两个64位宏操作处理,而在K10上通过单个宏操作完成128位存储器读取(K8上为2).

128位存储器读取指令仅使用K8上的FMISC单元,而是使用K10上的所有三个单元.因此,仅仅将XMM寄存器用于在k8上将数据块从一个存储器位置移动到另一个存储器位置是不利的,但是在K10上是有利的.