Bad*_*r99 3 c++ assembly gcc g++ simd
我有以下代码(最小示例):
#include <iostream>
#include <immintrin.h>
using namespace std;
int main(){
    __m128i a = _mm_set_epi32(rand(),rand(),rand(),rand());
    __m128i b = _mm_set_epi32(rand(),rand(),rand(),rand());
    __m128i c = _mm_add_epi32(a,b);
    int d[4];
    _mm_storeu_si128((__m128i*)d,c);
    cout<<d[0]<<endl;
    cout<<d[1]<<endl;
    cout<<d[2]<<endl;
    cout<<d[3]<<endl;
    return 0;
}
编译时g++ -O3 -march=native,它会产生一些奇怪/坏/低效的程序集(https://godbolt.org/z/TQgbim).它存储c一次,然后它执行一个对齐的加载和一个提取来进行元素访问(每次).我可以看到它为什么需要将它存储到内存中,我可以看到对齐的加载和提取如何有效,但我不明白为什么它需要在提取后继续将相同的数据加载到xmm寄存器中.此外,当d更改它以便在堆上分配(https://godbolt.org/z/Pk7qP2)时,它甚至不再执行对齐的加载,它只是视为d普通数组并访问元素办法.有人可以解释为什么这样做以及它可能带来什么好处?谢谢.
是的,这是一个有趣的错过优化.
看起来它决定优化矢量存储/标量重载到矢量提取,这通常是好的.
但它没有考虑调用约定,它没有调用保留的向量寄存器.这个代码在Windows x64上可以很好,例如,它可以使用xmm6.
如果您调用内联函数,或者将所有4个元素作为参数传递给同一函数,则此代码也可以正常运行.(例如printf).
GCC有多次通过,并且在程序逻辑的GIMPLE表示上运行的体系结构中立的中间通道有时无法利用在寄存器分配时间之前不知道的完整细节.一些优化对于gcc来说很难,因为它只是没有连线才能看到它们.
顺便说一句,如果你关心这个效率水平,请使用'\n'而不是endl.您不需要在cout那里明确刷新.