我正在尝试使用 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 个寄存器用于临时结果。恕我直言,这应该恰好适合 64 位目标可用的 16 个可用 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>
只是简单的 a struct
of 3 __m128
,通过标量进行自然加法和乘法运算。当该行a2 -= v
被注释掉时,即我们只需要 3x3 寄存器来存储,因为我们忽略a2
了 ,生成的代码确实很简单,没有移动,一切都在寄存器中执行xmm0-xmm10
。当我删除评论a2 -= v
时,代码非常糟糕,寄存器和堆栈之间有很多改组。即使编译器可以只使用寄存器xmm11-xmm13
或其他东西。
实际上,我还没有看到 GCCxmm11-xmm15
在我的所有代码中的任何地方使用任何寄存器。我究竟做错了什么?我知道它们是被调用者保存的寄存器,但是通过简化循环代码,这种开销是完全合理的。