g ++处理复制std :: complex

时间:2017-04-08 17:54:21

标签: c++ gcc assembly

作为自我教育项目的一部分,我研究了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 - 版本,但只需要16个字节,而movsd - 版本需要36个字节。

g ++使用movsd创建程序集的原因是什么?

  1. 还有一个额外的编译器标志来触发movups的使用,我应该在-O3旁边使用?
  2. 使用movups我不知道?
  3. 的缺点
  4. g ++在这里没有产生最佳装配?
  5. 别的什么?
  6. 更多上下文:我尝试比较两种可能的函数签名:

    std::complex<double> get(){
        return c;
    }
    

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

    由于SystemV ABI,第一个版本必须将实部和虚部放入不同的寄存器(xmm0xmm1)。但是对于第二个版本,人们可以尝试利用SSE操作的一些优点,这些优势可以在128位上运行,但是它不适用于我的g ++版本。

    编辑:正如肯尼特的回答所暗示的那样,g ++似乎产生了非最佳装配。它总是使用4个movsd将std :: complex从一个内存位置复制到另一个内存位置,例如在

    void get(std::complex<double> *res){
        res[1]=res[0];
    }
    

    现在有一个bug-report提交给gcc-bugzilla ..

1 个答案:

答案 0 :(得分:2)

3。 g ++不会在这里产生最佳装配。

clangicc都只使用一个SSE寄存器。您可以在https://godbolt.org/g/55lPv0中查看已编译的代码。

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