我试图在切换执行单元的域时理解旁路延迟。
例如,以下两行代码给出了完全相同的结果。
_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));
最好使用哪一行代码?
第一行的汇编输出给出:
vpslldq xmm1, xmm0, 8
vaddps xmm0, xmm1, xmm0
第二行的汇编输出给出:
vshufps xmm1, xmm0, XMMWORD PTR [rcx], 64 ; 00000040H
vaddps xmm2, xmm1, XMMWORD PTR [rcx]
现在,如果我看一下Agner Fog的微体系结构manual,他在第112页给出了一个例子,在浮点值上使用整数shuffle(pshufd),而在float值上使用float shuffle(shufps)。交换域增加了4个额外的时钟周期,因此使用shufps的解决方案更好。
我使用_mm_slli_si128
列出的第一行代码必须在整数和浮点向量之间切换域。使用_mm_shuffle_ps
的第二个停留在同一个域中。这是否意味着第二行代码是更好的解决方案?
答案 0 :(得分:6)
英特尔optimization guide中的第2.1.4节表明你(和Agner)在这件事上是对的 -
当在一个堆栈中执行的微操作的源来自在另一个堆栈中执行的微操作时,可能发生一个或两个周期的延迟。 英特尔SSE整数与英特尔SSE浮点运算之间的转换也会出现延迟。
所以一般情况下,你最好尽可能保持在同一个堆栈/域中。
当然,基准测试总是首选,只有在这确实是代码中的瓶颈的情况下才值得处理。