【发布时间】:2021-08-10 21:26:04
【问题描述】:
我知道“为什么我的编译器会这样做”不是最好的问题类型,但这个问题对我来说真的很奇怪,我完全糊涂了。
我原以为std::min()和手写的三元是一样的(可能有一些编译时模板的东西),正常使用时似乎编译成相同的操作。但是,当尝试使“最小和”循环自动矢量化时,它们似乎并不相同,如果有人能帮助我找出原因,我会很高兴。这是一个产生问题的小示例代码:
#pragma GCC target ("avx2")
#pragma GCC optimize ("O3")
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define N (1<<20)
char a[N], b[N];
int main() {
for (int i=0; i<N; ++i) {
a[i] = rand()%100;
b[i] = rand()%100;
}
int ans = 0;
#pragma GCC ivdep
for (int i=0; i<N; ++i) {
//ans += std::min(a[i], b[i]);
ans += a[i]>b[i] ? a[i] : b[i];
}
printf("%d\n", ans);
}
我在gcc 9.3.0 上编译它,使用编译命令g++ -o test test.cpp -ftree-vectorize -fopt-info-vec-missed -fopt-info-vec-optimized -funsafe-math-optimizations。
上面的代码在编译过程中调试为:
test.cpp:19:17: optimized: loop vectorized using 32 byte vectors
相比之下,如果我评论三元并取消评论 std::min,我会得到:
test.cpp:19:17: missed: couldn't vectorize loop
test.cpp:20:35: missed: statement clobbers memory: _9 = std::min<char> (_8, _7);
所以std::min() 似乎在做一些不寻常的事情,阻止 gcc 理解它只是一个最小操作。这是由标准引起的吗?还是实施失败?或者是否有一些编译标志可以使这项工作?
【问题讨论】:
-
似乎添加了
-O1或更高achieves the vectorization的优化级别。我怀疑这是函数内联的问题。 -
@MarekR 这不是过早的优化,在我的计算机上它加速了 >2 倍。我认为您的编译器资源管理器链接没有矢量化标志,因为 asm 输出没有矢量化指令(例如
vpaddd等) -
是的,除非您使用
-O,否则这些优化选项实际上都没有任何作用。特别是,没有-O,编译器将不会内联std::min,所以它知道它可能会修改全局变量a,b。 -
嗯,这是个好问题。快速阅读,
#pragma GCC optimize ("O3")相当于在每个函数上指定__attribute__((optimize("O3")))。但我可能猜测这不允许像内联这样的过程间优化,因此它可能不等同于在命令行上使用-O3。无论如何,这表明在实践中它们是不等价的。
标签: c++ gcc optimization compiler-optimization auto-vectorization