【发布时间】:2020-04-02 00:16:07
【问题描述】:
gcc/g++ 是否具有启用或禁用算术优化的标志,例如当a 是整数时,a+a+...+a 被n*a 替换?特别是在使用-O2 或-O3 时可以禁用此功能吗?
在下面的示例中,即使使用-O0,加法运算也会被单个乘法替换:
$ cat add1.cpp
unsigned int multiply_by_22(unsigned int a)
{
return a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a;
}
$ g++ -S -masm=intel -O0 add1.cpp
$ cat add1.s
...
imul eax, edi, 22
即使禁用-O0 中使用的所有标志(请参阅g++ -c -Q -O0 --help=optimizers | grep enabled)仍会产生imul 操作。
加循环时,需要-O1来简化单次乘法的重复加法:
$ cat add2.cpp
unsigned int multiply(unsigned int a, unsigned int b)
{
unsigned int sum=0;
for(unsigned int i=0; i<b; i++)
sum += a;
return sum;
}
$ g++ -S -masm=intel -O1 add2.cpp
$ cat add2.s
...
mov eax, 0
.L3:
add eax, 1
cmp esi, eax
jne .L3
imul eax, edi
ret
即-O1 已将 sum += a; 移到循环之外,并用一个乘法替换它。使用-O2,它也会移除死循环。
我只是出于兴趣而询问一些基本的整数运算,并注意到编译器优化了我的循环,我找不到任何标志来禁用它。
【问题讨论】:
-
我正在寻找一些可能会强制执行您所说的行为的编译指示,但我只发现 stackoverflow.com/questions/2219829/… 听起来不错......但所有答案都解释了如何在本地设置
-O0,并且我们知道这对你来说还不够。 -
大多没有这样的标志。您可以修改代码(添加 volatile,将操作放在单独的语句中)。对于有符号类型,未定义的清理程序也可能会阻止一些优化。
-
为什么要对在真实代码中从未发生过的事情进行计时?
-
@n.'pronouns'm。纯粹是为了时间
add、imul、idiv操作等,我知道网上有一些很好的手册,比如agner.org/optimize/instruction_tables.pdf,但在本地复制总是很好:) -
如果你想对某些汇编指令计时,请将这些准确的汇编指令写在汇编中。
标签: c gcc x86 compiler-optimization microbenchmark