在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
不是一种选择。但是,使用+
非常简单,可以说明问题。
答案 0 :(得分:3)
&#34;无关&#34; movq
正在清除__m128d
中的第二个元素,正如您在list-initialization __m128d{x}
中所请求的那样。
当源操作数是XMM寄存器时,移动低四字;当目标操作数是XMM寄存器时,四字存储到寄存器的低位四字,高位四字被清除为全0。
请记住,当提供的初始值设定项少于成员时,所有剩余的成员都会进行值初始化(为零)。
我希望更高级别的优化能够看到第二个元素从未使用过,并删除无关的指令。另一方面,即使未使用,在添加操作期间也不允许第二个值陷阱,并且明确地清除它可能是确保它没有的最安全的方法。