切换执行单元域时绕过延迟

Z b*_*son 7 assembly sse intel

我试图在切换执行单元的域时理解可能的旁路延迟.

例如,以下两行代码给出了完全相同的结果.

_mm_add_ps(x, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(x), 8)));
_mm_add_ps(x, _mm_shuffle_ps(_mm_setzero_ps(), x, 0x40));
Run Code Online (Sandbox Code Playgroud)

哪一行代码更好用?

第一行的汇编输出给出:

vpslldq xmm1, xmm0, 8
vaddps  xmm0, xmm1, xmm0
Run Code Online (Sandbox Code Playgroud)

第二行的汇编输出给出:

vshufps xmm1, xmm0, XMMWORD PTR [rcx], 64   ; 00000040H
vaddps  xmm2, xmm1, XMMWORD PTR [rcx]
Run Code Online (Sandbox Code Playgroud)

现在,如果我看一下Agner Fog的微体系结构手册,他给出了第112页的一个例子,在浮点值上使用整数shuffle(pshufd),而在float值上使用float shuffle(shufps).交换域增加了4个额外的时钟周期,因此使用shufps的解决方案更好.

我列出的第一行代码_mm_slli_si128必须在整数和浮点向量之间切换域.第二个使用_mm_shuffle_ps停留在同一个域中.这是否意味着第二行代码是更好的解决方案?

Lee*_*eor 7

英特尔优化指南中的第2.1.4节表明您(和Agner)在此问题上非常正确 -

当在一个堆栈中执行的微操作的源来自在另一个堆栈中执行的微操作时,可能发生一个或两个周期的延迟.对于英特尔SSE整数和英特尔SSE浮点运算之间的转换,也会发生延迟.

在此输入图像描述

所以一般来说,你最好尽可能地保持在同一个堆栈/域中.

当然,基准测试始终是首选,只有在这确实是代码瓶颈的情况下才值得处理.