作为自我教育项目的一部分,我研究了g ++如何处理std::complex
- 类型,并对这个简单的函数感到困惑:
#include <complex>
std::complex<double> c;
void get(std::complex<double> &res){
res=c;
}
Run Code Online (Sandbox Code Playgroud)
用Linux64 编译g++-6.3 -O3
(或者也是-Os
)我得到了这个结果:
movsd c(%rip), %xmm0
movsd %xmm0, (%rdi)
movsd c+8(%rip), %xmm0
movsd %xmm0, 8(%rdi)
ret
Run Code Online (Sandbox Code Playgroud)
因此它将实部和虚部单独移动为64位浮点数.但是,我希望程序集使用两个movups
而不是四个movsd
,即同时将实部和虚部移动为128位包:
movups c(%rip), %xmm0
movups %xmm0, (%rdi)
ret
Run Code Online (Sandbox Code Playgroud)
这不仅是我的机器(英特尔Broadwell)的两倍 - movsd
反转,而且只需要16个字节,而movsd
-version需要36个字节.
g ++创建程序集的原因是什么movsd
?
movups
我应该使用的旁边的用法-O3
?movups
我不知道有什么缺点?更多上下文:我尝试比较两个可能的函数签名:
std::complex<double> get(){
return c;
}
Run Code Online (Sandbox Code Playgroud)
和
void get(std::complex<double> &res){
res=c;
}
Run Code Online (Sandbox Code Playgroud)
由于SystemV ABI ,第一个版本必须将实部和虚部放入不同的寄存器(xmm0
和xmm1
)中.但是对于第二个版本,人们可以尝试利用在128位上运行的SSE操作的一些优点,但是它不适用于我的g ++版本.
编辑:正如kennytm的回答所示,g ++似乎产生非最优装配.它总是使用4个movsd将std :: complex从一个内存位置复制到另一个内存位置,例如在
void get(std::complex<double> *res){
res[1]=res[0];
}
Run Code Online (Sandbox Code Playgroud)
现在有一个错误报告提交给gcc-bugzilla ..
两者clang
都只 icc
使用一个 SSE 寄存器。您可以在https://godbolt.org/g/55lPv0中查看编译后的代码。
get(std::complex<double>&):
movups c(%rip), %xmm0
movups %xmm0, (%rdi)
ret
Run Code Online (Sandbox Code Playgroud)