-O0 比 -O3 更好的 gcc 优化

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