【问题标题】:Lambda vs. manually inlined code changes GCC's optimizer behaviorLambda vs. 手动内联代码改变了 GCC 的优化器行为
【发布时间】:2021-08-28 17:06:53
【问题描述】:

以下代码:

#include <vector>

extern std::vector<int> rng;

int main()
{
  auto is_even=[](int x){return x%2==0;};
  int res=0;
  for(int x:rng){
    if(is_even(x))res+=x;
  }

  return res;
}

由 GCC 11.1 (link to Godbolt) 以非常不同的方式优化:

#include <vector>

extern std::vector<int> rng;

int main()
{
  int res=0;
  for(int x:rng){
    if(x%2==0)res+=x;
  }

return res;
}

(Link to Godbolt.) 此外,第二个版本(其中 lambda 已被直接手动注入其主体代替调用位置)比第一个版本快得多。

这是 GCC 错误吗?

【问题讨论】:

  • 查看生成的程序集,带有 lambda 的版本没有自动矢量化,因此更快的第二个版本很有意义。
  • 这是直接在 Godbolt 中并排的,顺便说一句:godbolt.org/z/aYq5Gx3P8
  • 是的,但为什么 GCC 不使用 lambda 向量化?
  • Clang 似乎对两个版本都进行了矢量化,请参阅:godbolt.org/z/Txb4scMo4

标签: c++ gcc optimization lambda


【解决方案1】:

这是代码生成的一个怪癖。没有理由不应该对 lambda 版本进行矢量化。事实上,clang vectorizes it 原样。如果你指定返回类型为intGCC vectorizes it 也是:

auto is_even = [](int x) -> int { return x % 2 == 0; };

如果您使用std::accumulate,它也是vectorized。您可以将此问题报告给 GCC,以便他们修复。

【讨论】:

  • >您可以将此报告给 GCC,以便他们修复它。不幸的是,GCC Bugzilla 帐户的创建受到限制,并且手动请求 gcc-bugzilla-account-request@gcc.gnu.org 也被阻止。
【解决方案2】:

在 x64 架构中没有向量化积分模运算之类的东西。这意味着代码本身并不是可矢量化的,需要事先进行转换才能完成。

在使用 SIMD 友好的均匀度测试的更简单的情况下,您可以看到矢量化在这两种情况下都运行良好:https://godbolt.org/z/hc5ffbePY

因此,如果有的话,可以说 GCC 设法对内联版本进行矢量化,并且 Clang 内联这两个版本,实际上非常令人印象深刻。

话虽如此,由于我们知道 GCC 能够执行该转换,因此它似乎只在内联发生之前执行,这是不幸的,并且可能值得引起维护者的注意。

【讨论】:

  • std::accumulate 与 lambda 一起使用会生成矢量化代码。所以,我不认为这是 lambdas godbolt.org/z/GW4o1cGjG 的问题
  • @AyxanHaqverdili 这里并不是真正的苹果与橘子的比较。累积 lambda 与 OP 中的问题非常不同。
  • 查看我的答案:只需将 OP 代码中的返回类型从 bool 更改为 int 就会导致 GCC 对其进行矢量化。你知道他们说什么:如有疑问,请将bool 替换为int :-)
猜你喜欢
  • 2012-02-07
  • 2016-12-09
  • 1970-01-01
  • 2011-12-16
  • 2020-05-20
  • 1970-01-01
  • 1970-01-01
  • 2012-01-24
  • 1970-01-01
相关资源
最近更新 更多