作为自我教育项目的一部分,我研究了g++如何处理std::complex
-类型,并对此简单的功能感到困惑:
#include <complex>
std::complex<double> c;
void get(std::complex<double> &res){
res=c;
}
使用Linux64的
g++-6.3 -O3
(或-Os
)进行编译,我得到了以下结果: 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
有缺点吗? 更多内容:我尝试比较两个可能的函数签名:
std::complex<double> get(){
return c;
}
和
void get(std::complex<double> &res){
res=c;
}
由于SystemV ABI,第一个版本必须将实部和虚部放入不同的寄存器(
xmm0
和xmm1
)中。但是使用第二个版本时,可以尝试利用SSE操作的一些优势,该功能可以在128位上使用,但是不适用于我的g++版本。编辑:正如肯尼特姆(Kennytm)的答案所暗示,g++似乎产生了非最佳汇编。它总是使用4 movsd将std::complex从一个内存位置复制到另一个内存位置,例如
void get(std::complex<double> *res){
res[1]=res[0];
}
现在有一个bug-report归档到gcc-bugzilla。
最佳答案
3. g++在这里不能产生最佳的汇编。clang
和icc
都仅使用一个SSE寄存器。您可以在https://godbolt.org/g/55lPv0中检查编译后的代码。
get(std::complex<double>&):
movups c(%rip), %xmm0
movups %xmm0, (%rdi)
ret