【发布时间】:2017-04-08 17:54:21
【问题描述】:
作为自学项目的一部分,我研究了 g++ 如何处理std::complex - 类型,并对这个简单的函数感到困惑:
#include <complex>
std::complex<double> c;
void get(std::complex<double> &res){
res=c;
}
用g++-6.3 -O3(或-Os)为Linux64编译我得到了这个结果:
movsd c(%rip), %xmm0
movsd %xmm0, (%rdi)
movsd c+8(%rip), %xmm0
movsd %xmm0, 8(%rdi)
ret
因此它将实部和虚部分别移动为 64 位浮点数。但是,我希望程序集使用两个 movups 而不是四个 movsd,即将实部和虚部作为 128 位包同时移动:
movups c(%rip), %xmm0
movups %xmm0, (%rdi)
ret
这不仅在我的机器(Intel Broadwell)上是 movsd-version 的两倍,而且只需要 16 个字节,而 movsd-version 需要 36 个字节。
g++ 用movsd 创建程序集的原因是什么?
- 还有一个额外的编译器标志来触发
movups的使用,我应该在-O3旁边使用它吗? - 我不知道使用
movups有哪些缺点? - g++ 在这里没有产生最优的组装?
- 还有别的吗?
更多上下文:我尝试比较两个可能的函数签名:
std::complex<double> get(){
return c;
}
和
void get(std::complex<double> &res){
res=c;
}
由于 SystemV ABI,第一个版本必须将实部和虚部放入不同的寄存器(xmm0 和 xmm1)。但是对于第二个版本,可以尝试利用适用于 128 位的 SSE 操作的一些优势,但它不适用于我的 g++ 版本。
编辑:正如 kennytm 的回答所暗示的,g++ 似乎产生了非最佳程序集。它总是使用 4 movsd 将 std::complex 从一个内存位置复制到另一个内存位置,例如
void get(std::complex<double> *res){
res[1]=res[0];
}
现在有一个bug-report 提交给 gcc-bugzilla..
【问题讨论】:
-
我有
movsd c+8(%rip), %xmm1; movsd c(%rip), %xmm0使用 gcc.godbolt.org -
有趣的是,
godbolt.org的 output 与您的略有不同。这也可能是您的解释:由于这两个值都在不同的寄存器中返回,因此使用movups是没有意义的。