在 godbolt.org 上使用 gcc 7.2 我可以看到以下内容 code在汇编程序中的翻译非常优化。我看到 1 个加载、1 个添加和 1 个存储。
#include <immintrin.h>
__attribute__((alwaysinline)) double foo(double x, double y)
{
return x+y;
}
void usefoo(double x, double *y, double *z)
{
*z = foo(x, *y);
}
结果是:
usefoo(double, double*, double*):
addsd xmm0, QWORD PTR [rdi]
movsd QWORD PTR [rsi], xmm0
ret
但是,如果我尝试使用内部函数和模板与 code 实现相同的目标在下面,我可以看到增加了一些开销。特别是,该指令的意义是什么:movq xmm0, xmm0
?
#include <immintrin.h>
__attribute__((alwaysinline)) double foo(double x, double y)
{
return _mm_cvtsd_f64(_mm_add_sd(__m128d{x}, __m128d{y}));
}
void usefoo(double x, double *y, double *z)
{
*z = foo(x, *y);
}
结果是:
usefoo(double, double*, double*):
movq xmm1, QWORD PTR [rdi]
movq xmm0, xmm0
addsd xmm0, xmm1
movlpd QWORD PTR [rsi], xmm0
ret
如何使用标量内在函数实现与编译器否则生成的代码等效的代码?
如果您想知道我为什么要这样做,请考虑替换 +
与 <=
:如果我写x<y
编译器将结果转换为 bool,而内在函数会将其保留为双位掩码。因此,对于我的用例,写 x<y
不是一个选择。但是使用+
很简单足以说明问题。
最佳答案
“无关的”movq
正在清除 __m128d
中的第二个元素,按照列表初始化 __m128d{x}
的请求.
When the source operand is an XMM register, the low quadword is moved; when the destination operand is an XMM register, the quadword is stored to the low quadword of the register, and the high quadword is cleared to all 0s.
请记住,当提供的初始值设定项少于成员数量时,所有剩余成员都会进行值初始化(为零)。
我希望进行更高级别的优化,以确保第二个元素从未被使用,并删除无关的指令。另一方面,即使未使用,第二个值也不能在加法操作期间被捕获,并且显式清除它可能是确保它不会被捕获的最安全方法。
关于c++ - 如何最大限度地减少将 double 加载到使用标量 SIMD 内在函数的 simd 寄存器中的开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48055973/