c - 在 XMM 中反转两个压缩 double 时,对 SHUFPD 或 PSHUFD 有何偏好?

标签 c assembly shuffle sse2

今天的问题相当短。考虑以下玩具 C 程序 shuffle.c,用于反转寄存器 xmm0 中的两个压缩 double :

#include <stdio.h>

void main () {
  double x[2] = {0.0, 1.0};
  asm volatile (
    "movupd  (%[x]), %%xmm0\n\t"
    "shufpd  $1, %%xmm0, %%xmm0\n\t"  /* method 1 */
    //"pshufd  $78, %%xmm0, %%xmm0\n\t"  /* method 2 */
    "movupd  %%xmm0, (%[x])\n\t"
    :
    : [x] "r" (x)
    : "xmm0", "memory");
  printf("x[0] = %.2f, x[1] = %.2f\n", x[0], x[1]);
  }

空运行后:gcc -msse3 -o shuffle shuffle.c | ./test,两个方法/指令都会返回正确的结果x[0] = 1.00,x[1] = 0.00This page表示 shufpd 的延迟为 6 个周期,而 intel intrinsic guide表示 pshufd 只有 1 个周期的延迟。这听起来像是对 pshufd 的极大偏好。然而,该指令确实适用于压缩整数。当将其用于打包 double 时,是否会因“错误类型”而受到任何惩罚?

作为一个类似的问题,我还听说指令movapsmovapd小1个字节,并且它们通过从16位读取128位来完成相同的事情对齐的地址。那么我们是否可以始终使用前者来移动(在 XMM 之间)/加载(从内存)/存储(到内存)?这看起来很疯狂。我认为必须有一些理由来拒绝这一点。有人可以给我一个解释吗?谢谢。

最佳答案

您总是会得到正确的结果,但这对性能很重要。

首选对 FP 数据进行 FP 洗牌,这些数据将作为 FP 数学指令的输入(如 addpsvfma... ,而不是像 xorps 这样的 insn)。

这可以避免某些微架构(包括当前可能的英特尔芯片)上出现任何额外的旁路延迟延迟。请参阅Agner Fog's microarchitecture guide 。 AMD Bulldozer 系列在 vector 整数域中执行所有洗牌,因此无论您使用哪种洗牌,都会存在旁路延迟。

如果它可以节省指令,那么无论如何使用整数洗牌都是值得的。 (但通常情况恰恰相反,您想要使用 shufps 来组合来自两个整数 vector 的数据。在更多情况下这也没有问题,而且大多数情况下仅在 Nehalem、IIRC 上出现问题。)


http://x86.renejeschke.de/html/file_module_x86_id_293.html列出了 CPUID 0F3n/0F2n CPU 的延迟,即 Pentium4(系列 0xF 型号 2 (Northwood)/型号 3 (Prescott))。这些数字显然完全不相关,甚至与 Agner Fog 的 P4 表 shufpd 不匹配。 .

英特尔的内在函数指南有时也包含与实验测试不匹配的数字。请参阅Agner Fog's instruction tables以获得良好的延迟/吞吐量数据,以及了解详细信息的微架构指南。


<强> movapsmovapd :现有的微架构不关心您使用的内容。 future 有人有可能设计出保留 double 的 x86 CPU。与 float 分开的 vector 内部 vector ,但目前唯一的区别是 int 与 FP。

总是更喜欢ps当行为相同时的指令( xorps 超过 xorpdmovhps 超过 movhpd )。


一些编译器(也许是 gcc 和 clang,我忘了)会编译 _mm_store_si128整数 vector 存储到 movaps ,因为在任何现有硬件上都没有性能下降,而且它短了一个字节。

IIRC,使用 movaps 加载整数 vector 数据也没有性能缺点。/movups ,但我对此不太确定。

不过,使用错误的 mov 指令进行 reg-reg 移动有一个性能缺点。 movdqa xmm1, xmm2两个 FP 指令之间的关系对 Nehalem 来说很糟糕。


回复:您的内联汇编:

不需要是 volatile ,您可以删除 "memory"如果您使用 16 字节结构或类似 "+m" 的东西,则会造成破坏输入/输出操作数。或者 __m128d 的“+x” vector 寄存器操作数多变的。

除非您在内联汇编或独立函数中编写整个循环,否则从内在函数中获得的结果可能比从内联汇编中获得更好的结果。

请参阅标记 wiki 以获取我的内联 asm 指南的链接。

关于c - 在 XMM 中反转两个压缩 double 时,对 SHUFPD 或 PSHUFD 有何偏好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37180565/

相关文章:

c - 生成随机数的问题

c - 在 C 中遍历二维数组

assembly - masm32 中的 while 循环无限循环

R:随机排列选定维度的数组元素

algorithm - 将数组 2 个元素按 2 个随机洗牌

c - 奇怪的编译速度优化结果——IAR编译器

c - C中sizeof()的意义是什么?

c - 在 c 代码中显示溢出的工具

assembly - 为什么在 ARMv8 上可以使用 xzr 寄存器而不是文字 0?

java - Fisher-Yates (java) 与 Collections.shuffle