对 SHUFPD 或 PSHUFD 是否有偏好来反转 XMM 中的两个 packed double?
Any preference to SHUFPD or PSHUFD for reversing two packed double in an XMM?
今天的问题很短。考虑以下玩具 C 程序 shuffle.c
,用于反转寄存器 xmm0
中的两个打包双精度数:
#include <stdio.h>
void main () {
double x[2] = {0.0, 1.0};
asm volatile (
"movupd (%[x]), %%xmm0\n\t"
"shufpd , %%xmm0, %%xmm0\n\t" /* method 1 */
//"pshufd , %%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
,两者methods/instructions都会return得到正确的结果x[0] = 1.00, x[1] = 0.00
。 This page says that shufpd
has a latency of 6 cycles, while the intel intrinsic guide 表示 pshufd
只有 1 个周期的延迟。这听起来像是对 pshufd
的极大偏爱。但是,该指令确实适用于压缩整数。将它用于打包双打时,会不会有任何与 "wrong type" 相关的惩罚?
作为一个类似的问题,我也听说指令 movaps
比 movapd
小 1 个字节,它们通过从 16 位对齐地址读取 128 位来做同样的事情。那么我们是否总是可以使用前者进行移动(在 XMM 之间)/加载(从内存)/存储(到内存)?这看起来很疯狂。我认为必须有一些理由拒绝这一点。有人可以给我一个解释吗?谢谢。
您总是会得到正确的结果,但这对性能很重要。
对于将作为 FP 数学指令输入的 FP 数据(如 addps
或 vfma...
,而不是像 xorps
这样的 insns),首选 FP 洗牌。
这避免了某些微体系结构(包括可能当前的 Intel 芯片)上的任何额外旁路延迟延迟。参见 Agner Fog's microarchitecture guide。 AMD Bulldozer 系列在向量整数域中进行所有洗牌,因此无论您使用哪种洗牌,都会有旁路延迟。
如果它节省了指令,那么无论如何使用整数洗牌都是值得的。 (但通常情况恰恰相反,你想使用 shufps
来组合来自两个整数向量的数据。在更多情况下这很好,而且主要只在 Nehalem,IIRC 上才有问题。)
http://x86.renejeschke.de/html/file_module_x86_id_293.html 列出了 CPUID 0F3n/0F2n CPUs 的延迟,即 Pentium4(系列 0xF 模型 2(Northwood)/模型 3(Prescott))。这些数字显然完全无关紧要,甚至不匹配 Agner Fog 的 P4 table for shufpd
.
英特尔的内在函数指南有时也有与实验测试不匹配的数字。请参阅 Agner Fog's instruction tables 以获得良好的 latency/throughput 数字,以及微架构指南以了解详细信息。
movaps
vs. movapd
:没有现有的微架构关心你使用的是哪个。将来有人可能会设计一个 x86 CPU,使 double
向量在内部与 float
向量分开,但目前唯一的区别是 int 与 FP。
当行为相同时(xorps
优于 xorpd
,movhps
优于 movhpd
),始终首选 ps
指令。
一些编译器(可能是 gcc 和 clang,我忘记了)会将 _mm_store_si128
整数向量存储编译为 movaps
,因为任何现有硬件都没有性能下降,而且它更短一个字节.
IIRC,使用 movaps
/ movups
加载整数向量数据也没有性能缺点,但我不太确定。
不过, 对 reg-reg 移动使用错误的 mov 指令会带来性能上的不利影响。 movdqa xmm1, xmm2
在 Nehalem 上两个 FP 指令之间是错误的。
回复:你的内联汇编:
它不需要是 volatile
,如果您使用 16 字节结构或类似 "+m"
input/output 的东西,您可以删除 "memory"
破坏符操作数。或 __m128d
变量的“+x”向量寄存器操作数。
与内联 asm 相比,内联函数可能会获得更好的结果,除非您在内联 asm 或独立函数中编写整个循环。
请参阅 x86 标签 wiki 以获得 link 我的内联 asm 指南。
今天的问题很短。考虑以下玩具 C 程序 shuffle.c
,用于反转寄存器 xmm0
中的两个打包双精度数:
#include <stdio.h>
void main () {
double x[2] = {0.0, 1.0};
asm volatile (
"movupd (%[x]), %%xmm0\n\t"
"shufpd , %%xmm0, %%xmm0\n\t" /* method 1 */
//"pshufd , %%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
,两者methods/instructions都会return得到正确的结果x[0] = 1.00, x[1] = 0.00
。 This page says that shufpd
has a latency of 6 cycles, while the intel intrinsic guide 表示 pshufd
只有 1 个周期的延迟。这听起来像是对 pshufd
的极大偏爱。但是,该指令确实适用于压缩整数。将它用于打包双打时,会不会有任何与 "wrong type" 相关的惩罚?
作为一个类似的问题,我也听说指令 movaps
比 movapd
小 1 个字节,它们通过从 16 位对齐地址读取 128 位来做同样的事情。那么我们是否总是可以使用前者进行移动(在 XMM 之间)/加载(从内存)/存储(到内存)?这看起来很疯狂。我认为必须有一些理由拒绝这一点。有人可以给我一个解释吗?谢谢。
您总是会得到正确的结果,但这对性能很重要。
对于将作为 FP 数学指令输入的 FP 数据(如 addps
或 vfma...
,而不是像 xorps
这样的 insns),首选 FP 洗牌。
这避免了某些微体系结构(包括可能当前的 Intel 芯片)上的任何额外旁路延迟延迟。参见 Agner Fog's microarchitecture guide。 AMD Bulldozer 系列在向量整数域中进行所有洗牌,因此无论您使用哪种洗牌,都会有旁路延迟。
如果它节省了指令,那么无论如何使用整数洗牌都是值得的。 (但通常情况恰恰相反,你想使用 shufps
来组合来自两个整数向量的数据。在更多情况下这很好,而且主要只在 Nehalem,IIRC 上才有问题。)
http://x86.renejeschke.de/html/file_module_x86_id_293.html 列出了 CPUID 0F3n/0F2n CPUs 的延迟,即 Pentium4(系列 0xF 模型 2(Northwood)/模型 3(Prescott))。这些数字显然完全无关紧要,甚至不匹配 Agner Fog 的 P4 table for shufpd
.
英特尔的内在函数指南有时也有与实验测试不匹配的数字。请参阅 Agner Fog's instruction tables 以获得良好的 latency/throughput 数字,以及微架构指南以了解详细信息。
movaps
vs. movapd
:没有现有的微架构关心你使用的是哪个。将来有人可能会设计一个 x86 CPU,使 double
向量在内部与 float
向量分开,但目前唯一的区别是 int 与 FP。
当行为相同时(xorps
优于 xorpd
,movhps
优于 movhpd
),始终首选 ps
指令。
一些编译器(可能是 gcc 和 clang,我忘记了)会将 _mm_store_si128
整数向量存储编译为 movaps
,因为任何现有硬件都没有性能下降,而且它更短一个字节.
IIRC,使用 movaps
/ movups
加载整数向量数据也没有性能缺点,但我不太确定。
不过, 对 reg-reg 移动使用错误的 mov 指令会带来性能上的不利影响。 movdqa xmm1, xmm2
在 Nehalem 上两个 FP 指令之间是错误的。
回复:你的内联汇编:
它不需要是 volatile
,如果您使用 16 字节结构或类似 "+m"
input/output 的东西,您可以删除 "memory"
破坏符操作数。或 __m128d
变量的“+x”向量寄存器操作数。
与内联 asm 相比,内联函数可能会获得更好的结果,除非您在内联 asm 或独立函数中编写整个循环。
请参阅 x86 标签 wiki 以获得 link 我的内联 asm 指南。