所以基本上,对于我的项目,有一个限制,它不能使用-O3标志(我们必须只使用-O2)。这样做的原因是-O3标志显然引入了"硬件加速指令"。
gcc版本为5.4,此版本优化标记的手册页为:this
我希望尽可能多地包含-O3&#39的标志。 -O3引入的标志列表是:
-finline-functions, -funswitch-loops, -fpredictive-commoning, -fgcse-after-reload, -ftree-loop-vectorize, -ftree-loop-distribute-patterns, -ftree-slp-vectorize, -fvect-cost-model, -ftree-partial-pre and -fipa-cp-clone
所以我打算使用-O2并手动包含尽可能多的上述标志。
上面的哪些标志启用"硬件加速指令"优化?如何判断标志是否支持硬件加速指令"通过阅读描述进行优化?是什么构成的?
答案 0 :(得分:4)
使用的指令集由-march
控制,而不是由-O3
控制。确实,-O3
可能会更多地使用SIMD指令进行矢量化,但-O3
并未在代码生成期间专门添加或删除指令。
如果您只想使用最简单的说明编译代码,请为您的平台选择最简单的march
。例如,-march=core2
对于x86-64来说是一个保守的选择,因为它指的是相当老的英特尔酷睿2处理器系列。
仍然,Core 2支持到SSE3和SSSE3的MMX和SSE。要禁用它们,请添加:
-mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-ssse3
答案 1 :(得分:2)
我觉得约翰已经回答了这个问题,我会尝试提供一些例子。
考虑遵循最小程序:
#include <cstring>
void copy(long *dst , const long *src)
{
std::memcpy(dst, src, sizeof(long) * 4);
}
使用GCC 7.2 g++ -O2
在x86_64编译,得到以下输出:
copy(long*, long const*):
movdqu (%rsi), %xmm0
movups %xmm0, (%rdi)
movdqu 16(%rsi), %xmm0
movups %xmm0, 16(%rdi)
ret
使用GCC 7.2 g++ -O2 -mno-sse
在x86_64编译,得到以下输出:
copy(long*, long const*):
movq (%rsi), %rax
movq %rax, (%rdi)
movq 8(%rsi), %rax
movq %rax, 8(%rdi)
movq 16(%rsi), %rax
movq %rax, 16(%rdi)
movq 24(%rsi), %rax
movq %rax, 24(%rdi)
ret
如您所见,GCC甚至可以在-O2
级别生成SSE指令。需要使用单独的标志来禁止生成这些指令。
与此同时,GCC 5.4生成带有和不带-mno-sse
标志的相同代码,但它对-O3
优化级别也是如此。
所以你的目标在这里有点误导。在某些情况下,使用-O2
标志的超集可能会抑制SSE和类似指令的生成,但这并不能保证,因为优化级别仅与生成的指令间接相关。如果你真的想要压制它们,你可以使用-mno-sse
标志,但这可能会让你处于劣势。坚持-O2
- 这样每个人都将处于平等的地位。
我用https://godbolt.org/来证明这一点。
答案 2 :(得分:1)
我想补充几个。
你的电讯局长说:
使用-O3启用硬加速指令,例如SSE
我认为这不太正确。似乎-f选项旨在与机器无关。编译器解析源代码并将其转换为通常称为中间表示(IR)的东西。接下来,编译器优化IR本身,即所谓的机器独立。然后,从优化的IR生成汇编代码。生成程序集时,将应用一组不同的优化。 IR的例子是LLVM IR,Sun IR,GCC gimple tree和/或RTL等。我相信所有现代编译器都有IR(s)。
我相信GCC的-f选项基本上是与机器无关的。 -m选项用于依赖于机器的优化。 -O2或-O3确定-f选项,理想情况下与机器无关。使用花哨的指令取决于编译器的机器相关部分。
实际上,机器相关和机器无关的世界之间的边界线可能不是很清楚。
由-O3打开的矢量化将是灰色区域中的优化示例。有些机器不支持SIMD。例如,有些但矢量大小与架构不同。这是我的示例代码:
// code.c
long long int inner_product(int* v0, int* v1, int sz) {
long long int res = 0;
for (int i = 0; i < sz; i++) {
res += (v0[i] * v1[i]);
}
return res;
}
如果编译如下:
$ gcc -O3 -S -march=core2 code.c -o code.s -fdump-tree-all
Gcc对其进行矢量化,但矢量大小为2 long long int或4 ints:
$ cat code.*.optimized | grep 'vector('
vector(2) long long int vect_res_16.21;
vector(2) long long int vect_res_16.19;
vector(2) long long int vect__8.18;
vector(4) int vect__7.17;
vector(4) int vect__6.16;
vector(4) int * vectp_v1.15;
vector(4) int vect__4.13;
vector(4) int * vectp_v0.12;
另一方面,如果使用-march = skylake-avx512编译,其矢量大小是core2的4倍,结果将是:
$ gcc -O3 -S -march=skylake-avx512 code.c -o code.s -fdump-tree-all && cat code.*.optimized | grep 'vector('
vector(8) long long int vect_res_16.21;
vector(8) long long int vect_res_16.19;
vector(8) long long int vect__8.18;
vector(16) int vect__7.17;
vector(16) int vect__6.16;
vector(16) int * vectp_v1.15;
vector(16) int vect__4.13;
vector(16) int * vectp_v0.12;
请注意,此时代码生成尚未开始。根据行军价值,IR看起来不同。我猜矢量化不是显示这种行为的唯一例子。
尽管如此,我认为将这种优化称为机器依赖是不公平的。典型的机器相关优化是指令调度。它几乎与中间表示无关。它更多地是关于机器指令和微架构。对于灰色区域中与机器无关的优化,从概念上讲,编译器可以生成统一的矢量化IR(例如,使矢量大小始终为4),并让代码生成器处理它(每个代码生成器可能需要合并或拆分矢量操作数)。然而,在实现中,给予向量操作数适当的大小在IR级别比在代码生成级别更容易。所以,我猜人们放弃了生活在&#34;想法的世界。&#34;尽管如此,我认为机器无关的优化可以称为与机器无关的。
您可能需要询问TA不希望看到哪种花哨的说明。如果这只是向量指令,则应禁用所有与向量相关的标志,但可以使用-O3。我的示例代码可用于查看是否仍有SIMD指令:
$ gcc -O3 -S code.c
$ cat code.s | egrep xmm
如果输出为空,那你很好。