gcc - 如何强制gcc使用所有SSE(或AVX)寄存器?

标签 gcc 64-bit sse register-allocation avx

我正在尝试使用SSE或新的AVX指令为Windows x64目标编写一些计算量大的代码,并在GCC 4.5.2和4.6.1,MinGW64(TDM GCC构建和一些自定义构建)中进行编译。我的编译器选项是-O3 -mavx。 (暗含-m64)

简而言之,我想对打包浮点数的4个3D向量进行一些冗长的计算。这需要4x3 = 12 xmm或ymm寄存器进行存储,并需要2或3个寄存器来获得临时结果。 IMHO应该恰好适合16位可用于64位目标的SSE(或AVX)寄存器。但是,GCC仅使用寄存器xmm0-xmm10以及将数据从堆栈中移出堆栈,就产生了寄存器溢出的非常不理想的代码。我的问题是:

是否有办法说服GCC使用所有寄存器xmm0-xmm15

要修正想法,请考虑以下SSE代码(仅用于说明):

void example(vect<__m128> q1, vect<__m128> q2, vect<__m128>& a1, vect<__m128>& a2) {
    for (int i=0; i < 10; i++) {
        vect<__m128> v = q2 - q1;
        a1 += v;
//      a2 -= v;

        q2 *= _mm_set1_ps(2.);
    }
}

这里vect<__m128>只是3 struct__m128,具有自然的加法和标量乘法。当a2 -= v行被注释掉时,即我们只需要3x3寄存器来存储,因为我们忽略了a2,因此生成的代码确实很简单,没有任何 Action ,所有操作都在寄存器xmm0-xmm10中执行。当我删除注释a2 -= v时,代码非常糟糕,寄存器和堆栈之间经过大量改组。即使编译器可以只使用寄存器xmm11-xmm13之类的东西。

我实际上还没有看到GCC在我所有代码中的任何地方都使用xmm11-xmm15寄存器。我究竟做错了什么?我知道它们是被调用者保存的寄存器,但是通过简化循环代码可以完全证明这种开销。

最佳答案

两点:

  • 首先,您要进行很多假设。在x86 CPU上,寄存器溢出非常便宜(由于快速的L1高速缓存和寄存器阴影以及其他技巧),并且仅64位寄存器的访问成本更高(就更大的指令而言),因此可能只是GCC的版本比您想要的速度快或快。
  • 其次,GCC与任何编译器一样,尽其所能来实现最佳寄存器分配。没有“请做更好的寄存器分配”选项,因为如果有的话,将始终启用它。编译器不会试图惹您生气。 (我记得,寄存器分配是一个NP完全问题,因此编译器将永远无法生成完美的解决方案。它能做的最好是近似值)

  • 因此,如果您想更好地分配寄存器,则基本上有两个选择:
  • 编写一个更好的寄存器分配器,并将其修补到GCC或
  • 绕过GCC并在汇编中重写该函数,因此您可以精确控制何时使用哪些寄存器。
  • 关于gcc - 如何强制gcc使用所有SSE(或AVX)寄存器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5960707/

    相关文章:

    visual-c++ - Visual C++ 中是否有 X64 固有的 8 位原子 CAS (cmpxchg)?

    c - SSE 16 位寄存器的无符号/有符号减法

    c - SSE加载和添加

    linux - 在 rhel 上从源代码安装 gcc-5.3.0

    c++ - Intel 64(EM64T)系统上char类型的大小

    c++ - “lock cmpxchg”如何在汇编中工作?

    python - 使用python 64位运行32位程序

    assembly - 与内在函数等价的 SSE2 汇编是什么?

    c - C 中的带符号二进制表示

    c - gcc 如何处理数组 [ 与 C 编程相关的问题 ]