EOF*_*EOF 6 gcc simd compiler-optimization avx2
我最近制作了一些矢量代码和一个合适的Godbolt 示例。
typedef float v8f __attribute__((vector_size(32)));
typedef unsigned v8u __attribute__((vector_size(32)));
v8f f(register v8f x)
{
return __builtin_shuffle(x, (v8f){0}, (v8u){1, 2, 3, 4, 5, 6, 7, 8});
}
Run Code Online (Sandbox Code Playgroud)
f:
vmovaps ymm1, ymm0
vxorps xmm0, xmm0, xmm0
vperm2f128 ymm0, ymm1, ymm0, 33
vpalignr ymm0, ymm0, ymm1, 4
ret
Run Code Online (Sandbox Code Playgroud)
我想看看不同的优化 ( -O0/O1/O2/O3) 设置如何影响代码,并且几乎都-O0给出了相同的代码。-O0给出了可预测的帧指针垃圾,并且x无缘无故地将参数复制到堆栈局部变量。为了解决这个问题,我添加了register存储类说明符:
typedef float v8f __attribute__((vector_size(32)));
typedef unsigned v8u __attribute__((vector_size(32)));
v8f f(register v8f x)
{
return __builtin_shuffle(x, (v8f){0}, (v8u){1, 2, 3, 4, 5, 6, 7, 8});
}
Run Code Online (Sandbox Code Playgroud)
对于-O1/O2/O3,生成的代码是相同的,但在-O0:
f:
vxorps xmm1, xmm1, xmm1
vperm2f128 ymm1, ymm0, ymm1, 33
vpalignr ymm0, ymm1, ymm0, 4
ret
Run Code Online (Sandbox Code Playgroud)
gcc想出如何避免冗余寄存器副本。虽然这样的副本可能会被移动消除,但这仍然会增加代码大小而没有任何好处(-Os大于-O0?)。
如何/为什么gcc产生在这个更好的代码-O0比-O3?