C++编译器对带有指针复制的循环的优化



我在godbolt.org上用-O2编译了这段代码,编译器并没有使用一些memcpy来优化它,而是诚实地运行循环。

void foo(int* dst, int* src, int n)
{
for (int i = 0; i < n; ++i)
{
dst[i] = src[i];
}
}

但是如果我替换"=src[i]";其中"=0";不过他们使用memset。但是,当我用"=1〃;,它们循环运行。当要设置的值不为零时,它们为什么要避免memcpy和memset?我认为这是他们将执行的第一个优化。

srcdest指向的范围可能重叠,在这种情况下,memcpy的行为将是未定义的。因此,将此函数优化为仅调用memcpy是不合适的。


memmove是合适的,但当srcdest范围重叠时,其行为与您的函数不同。考虑以下内容:

int arr[5] = {1, 2, 3, 4, 5};
foo(arr + 1, arr, 4);

您的函数将在调用后生成包含{1, 1, 1, 1, 1}arr,而指定memmove将生成包含{1, 1, 2, 3, 4}arr。因此编译器也不能将foo优化为对memmove的调用。


C在C99中添加了restrict关键字,以告诉编译器两个范围不会重叠,但C++没有采用该特定功能。

完成@MilesBudnek:的好答案

memset字节粒度工作,而您使用的int通常大于1个字节(4个字节(。这就是为什么编译器不能容易地用memset替换赋值= 1的原因。

还要注意的是,-O2并不能为GCC启用矢量化,尽管它显然为Clang启用了。GCC需要-ftree-vectorize(包括在-O3中(来生成更快的SIMD指令(在许多平台上不如memcpy/memmove/memset快(。

最新更新