[英]std::min vs ternary gcc auto vectorization with #pragma GCC optimize ("O3")
我知道“为什么我的编译器这样做”不是最好的问题类型,但这对我来说真的很奇怪,我完全糊涂了。
我曾认为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);
}
我使用编译命令g++ -o test test.cpp -ftree-vectorize -fopt-info-vec-missed -fopt-info-vec-optimized -funsafe-math-optimizations
在gcc 9.3.0
上编译它。
上面的代码在编译期间调试为:
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 理解它只是一个最小操作。 这是由标准引起的吗? 还是实施失败? 或者是否有一些编译标志可以使这项工作?
摘要:不要使用#pragma GCC optimize
。 在命令行上使用-O3
代替,您将获得您期望的行为。
GCC 关于#pragma GCC optimize
的文档说:
在此之后定义的每个 function 都被视为已为每个字符串参数声明了一个
optimize(string)
属性。
optimize 属性用于指定 function 将使用不同于命令行指定的优化选项进行编译。 [...] optimize 属性应仅用于调试目的。 它不适合生产代码。 [强调补充,感谢彼得科德斯发现最后一部分。]
所以,不要使用它。
特别是,看起来在文件顶部指定#pragma GCC optimize ("O3")
实际上并不等同于在命令行上使用-O3
。 事实证明,前者不会导致std::min
被内联,因此编译器实际上确实假设它可能会修改全局 memory,例如您a,b
arrays。 这自然会抑制矢量化。
仔细阅读__attribute__((optimize))
的文档,看起来每个函数main()
和std::min()
都将像使用-O3
一样编译。 但这与将它们两者与-O3
一起编译不同,因为只有在后一种情况下才可以使用内联等过程间优化。
这是关于 godbolt 的一个非常简单的例子。 使用#pragma GCC optimize ("O3")
函数foo()
和please_inline_me()
都进行了优化,但please_inline_me()
没有内联。 但是在命令行上使用-O3
就可以了。
猜测可能是optimize
属性和扩展#pragma GCC optimize
导致编译器将 function 视为其定义位于使用指定选项编译的单独源文件中。 事实上,如果std::min()
和main()
在单独的源文件中定义,您可以使用-O3
编译每个文件,但不会内联。
可以说 GCC 手册应该更明确地记录这一点,尽管我想如果它只是用于调试,假设它是为熟悉这种区别的专家准备的可能是公平的。
如果您确实在命令行上使用-O3
编译了您的示例,那么您将获得两个版本的相同(矢量化)程序集,或者至少我做到了。 (修复向后比较后:您的三元代码正在计算最大值而不是最小值。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.