比 LLVM 中的 floor/ceil/int 慢得多

round much slower than floor/ceil/int in LLVM

我通过执行以下循环对一些基本例程进行基准测试:

float *src, *dst;
for (int i=0; i<cnt; i++) dst[i] = round(src[i]);

全部采用 AVX2 目标,最新的 CLANG。有趣的是 floor(x)、ceil(x)、int(x)... 看起来都很快。但是 round(x) 似乎非常慢,并且在反汇编中有一些奇怪的意大利面条代码,而不是较新的 SSE 或 AVX 版本。即使通过引入一些依赖性来阻止向量化循环的能力,round 也会慢 10 倍。对于地板等,生成的代码使用 vroundss,对于圆形,有意大利面条代码...有什么想法吗?

编辑:我正在使用 -ffast-math、-mfpmath=sse、-fno-math-errno、-O3、-std=c++17、-march=core-avx2 -mavx2 -mfma

需要注意的一件事是,像 floor(x + 0.5) 这样的表达式虽然没有与 round(x) 完全相同的语义,但在几乎所有用例中都是有效的替代,我怀疑它是任何地方都比 floor(x).

慢 10 倍

问题是 none 的 SSE 舍入模式为 round 指定了正确的舍入:

These functions round x to the nearest integer, but round halfway cases away from zero (regardless of the current rounding direction, see fenv(3)), instead of to the nearest even integer like rint(3).

如果您想要更快的代码,您可以尝试测试 rint 而不是 round,因为它指定了 SSE 支持的舍入模式。