【问题标题】:C++ compiler optimization of a loop with pointers copying带有指针复制的循环的 C++ 编译器优化
【发布时间】:2020-11-29 22:56:24
【问题描述】:

我在 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 ?我认为这是他们将执行的首批优化之一。

【问题讨论】:

  • g++clang++ 似乎都可以更好地优化 std::copy_n(src, n, dst);(无论如何你都应该使用它)
  • 我认为 memcpy 永远不会与该函数签名一起使用。如果数组重叠,memcpy 会导致 UB。 memmove 更有可能。使用template&lt;unsigned N&gt; void foo(int (&amp;dst)[N], int (&amp;src)[N]) { { for(unsigned i = 0; i &lt; N; ++i) { dst[i] = src[i]; } } 你会得到memcpyclang++rep movsqg++

标签: c++ performance loops optimization compiler-optimization


【解决方案1】:

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


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

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

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


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

【讨论】:

    【解决方案2】:

    完成@MilesBudnek 的好回答:

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

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

    【讨论】:

      猜你喜欢
      • 2012-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-04
      相关资源
      最近更新 更多