作为自我教育项目的一部分,我研究了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有缺点吗?
  • g++在这里不能产生最佳汇编吗?
  • 还有别的吗?


  • 更多内容:我尝试比较两个可能的函数签名:
    std::complex<double> get(){
        return c;
    }
    


    void get(std::complex<double> &res){
        res=c;
    }
    

    由于SystemV ABI,第一个版本必须将实部和虚部放入不同的寄存器(xmm0xmm1)中。但是使用第二个版本时,可以尝试利用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++在这里不能产生最佳的汇编。
    clangicc都仅使用一个SSE寄存器。您可以在https://godbolt.org/g/55lPv0中检查编译后的代码。

    get(std::complex<double>&):
            movups    c(%rip), %xmm0
            movups    %xmm0, (%rdi)
            ret
    

    07-25 21:36