代码之家  ›  专栏  ›  技术社区  ›  BadProgrammer99

gcc的奇怪/错误的程序集输出?

  •  3
  • BadProgrammer99  · 技术社区  · 6 年前

    #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 ),它甚至不再做对齐的加载,它只是处理 作为一个普通数组并以这种方式访问元素。有人能解释一下它为什么这么做,它能带来什么好处吗?谢谢。

    1 回复  |  直到 6 年前
        1
  •  5
  •   Peter Cordes Steve Bohrer    6 年前

    是的,这是一个有趣的错过优化。

    看起来它决定优化向量存储/标量重新加载到向量提取,这通常是好的。

    但是它没有考虑调用约定,调用约定没有保留调用的向量寄存器。这段代码在Windows x64上就可以了,例如,它可以使用xmm6。

    printf

    GCC有多个进程,在程序逻辑的通用表示上操作的与体系结构无关的中间进程有时无法利用直到寄存器分配时间才知道的全部细节。对于gcc来说,有些优化是很困难的,因为它不能看到它们。


    '\n' 而不是 endl cout 在那里。