g ++处理复制std :: complex

ead*_*ead 6 c++ assembly gcc

作为自我教育项目的一部分,我研究了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

  1. 还有一个额外的编译器标志来触发movups我应该使用的旁边的用法-O3
  2. 使用movups我不知道有什么缺点?
  3. g ++在这里不会产生最佳装配?
  4. 别的什么?

更多上下文:我尝试比较两个可能的函数签名:

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 ,第一个版本必须将实部和虚部放入不同的寄存器(xmm0xmm1)中.但是对于第二个版本,人们可以尝试利用在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 ..

ken*_*ytm 2

3. g++ 在这里不产生最佳汇编。

两者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)