c++ - Lambda vs. 手动内联代码改变了 GCC 的优化器行为
问题描述
以下代码:
#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 (链接到 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;
}
(链接到 Godbolt。)此外,第二个版本(其中 lambda 已被直接手动注入其主体替换为调用位置),比第一个版本快得多。
这是 GCC 错误吗?
解决方案
在 x64 架构中没有向量化积分模运算之类的东西。这意味着代码本身并不是固有的可矢量化的,需要事先进行转换才能完成。
在使用 SIMD 友好的均匀度测试的更简单的情况下,您可以看到矢量化在这两种情况下都工作得很好:https ://godbolt.org/z/hc5ffbePY
因此,如果有的话,可以说 GCC 设法对内联版本进行矢量化,并且 Clang 内联这两个版本实际上非常令人印象深刻。
话虽如此,由于我们知道 GCC 能够执行该转换,因此它似乎只在内联发生之前执行,这是不幸的,并且可能值得引起维护者的注意。
推荐阅读
- java - 如何检查用户已注册并在 firebase 身份验证数据和 firebase 实时数据库之间匹配数据?
- python - == 并且即使比较 int 也不会返回相同的值
- reactjs - 反应按钮悬停?
- r - 查找重复值并具有引用
- google-analytics - DataStudio Google Analytics 连接器显示某些指标为零
- python-3.x - 在 python 中创建对象并与其他对象分离
- sql-server - 为什么“如果不存在”在维护计划中不起作用?
- python - Celery 任务在没有 celerybeat 的情况下成功后调用自身
- sql-server - 使用 SQL Server/ADO 替代 Index + Seek on Access/DAO
- javascript - 根据条件数组递归过滤对象数组