我recently编写了一些矢量代码和一个适当的godbolt example。
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});
}
f:
vmovaps ymm1, ymm0
vxorps xmm0, xmm0, xmm0
vperm2f128 ymm0, ymm1, ymm0, 33
vpalignr ymm0, ymm0, ymm1, 4
ret
我想看看不同的优化(-O0/O1/O2/O3
)设置如何影响代码,除-O0
之外的所有代码都提供了相同的代码。 -O0
产生了可预测的帧指针垃圾,并且也没有任何理由将参数x
复制到堆栈局部变量。为了解决这个问题,我added 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});
}
对于-O1/O2/O3
,生成的代码是相同的,但是在-O0
处:
f:
vxorps xmm1, xmm1, xmm1
vperm2f128 ymm1, ymm0, ymm1, 33
vpalignr ymm0, ymm1, ymm0, 4
ret
gcc
指出了如何避免冗余的寄存器复制。尽管这样的副本可能会被移动消除,但这仍然增加了代码大小,毫无益处(-Os
比-O0
大吗?)。
与gcc
相比,-O0
如何/为什么在-O3
上生成更好的代码?