我正在尝试为Windows x64目标编写一些计算密集型代码,使用SSE或新的AVX指令,在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>
只是struct
的3 __m128
,自然添加和标量乘法。当行a2 -= v
被注释掉时,即我们只需要3x3寄存器进行存储,因为我们忽略a2
,所产生的代码确实很简单,没有移动,所有内容都在寄存器xmm0-xmm10
中执行。当我删除注释a2 -= v
时,代码非常糟糕,寄存器和堆栈之间有很多混乱。即使编译器只能使用寄存器xmm11-xmm13
或其他东西。
我实际上还没有看到GCC在我的所有代码中的任何位置使用任何寄存器xmm11-xmm15
。我究竟做错了什么?我知道它们是被调用者保存的寄存器,但这种开销通过简化循环代码是完全合理的。
答案 0 :(得分:13)
两点:
所以,如果你想要更好的寄存器分配,你基本上有两个选择:
答案 1 :(得分:5)
实际上,你看到的不是溢出,是gcc在内存中的a1和a2上运行,因为它无法知道它们是否有别名。如果将最后两个参数声明为vect<__m128>& __restrict__
,GCC可以并将注册分配a1和a2。