我已阅读各种优化指南,声称ADD 1比在x86中使用INC更快。这是真的吗?
答案 0 :(得分:28)
在一些微架构上,对于某些指令流,INC
将导致“部分标志更新停顿”(因为它会在保留其他标志的同时更新一些标志)。 ADD
设置所有标志的值,因此不会冒这样的失误。
ADD
并不总是比INC
更快,但它几乎总是至少一样快(在某些较旧的微架构上存在一些极端情况,但它们非常罕见),并且有时会明显加快。
有关详细信息,请参阅Intel's Optimization Reference Manual或Agner Fog's micro-architecture notes。
答案 1 :(得分:4)
虽然这不是一个明确的答案。写下这个C文件:
=== inc.c ===
#include <stdio.h>
int main(int argc, char *argv[])
{
for (int n = 0; n < 1000; n++) {
printf("%d\n", n);
}
return 0;
}
然后运行:
clang -march=native -masm=intel -O3 -S -o inc.clang.s inc.c
gcc -march=native -masm=intel -O3 -S -o inc.gcc.s inc.c
请注意生成的汇编代码。相关的铿锵声:
mov esi, ebx
call printf
inc ebx
cmp ebx, 1000
jne .LBB0_1
相关的gcc输出:
mov edi, 1
inc ebx
call __printf_chk
cmp ebx, 1000
jne .L2
这证明了clang和gcc的作者都认为INC
在现代架构上比ADD reg, 1
更好。INC
。
这对你的问题意味着什么?好吧,我相信他们对你读过的指南的判断,并得出结论:ADD
和-march=native
一样快,并且由于寄存器编码较短而节省的一个字节使它更受欢迎。编译器作者只是人,所以他们可能是错的,但不太可能。 :)
更多实验告诉我,如果您不使用add ebx, 1
选项,那么gcc将使用ADD
代替。 Clang otoh,总是喜欢最好的。我的结论是,当您在2012年提出问题INC
时,有时候会更好,但现在在2016年,您应该始终使用{{1}}。
答案 2 :(得分:-1)
在80年代或90年代的简单指令执行时间主要取决于指令中的组件数量:添加ax,1包含一个可解码单位(立即数),与inc,或者添加ax,bx相比。因此,80286花费了一个时钟周期来解码指令。
然后是时代,当英特尔以CISC类型指令为代价特别优化了大多数RISC类型的指令。 (例如,添加ax,[mem];添加[mem],ax)。今天或者至少明天,这些都很便宜......复杂的分支序列将在30个单元的流水线中解析,自动重新命名。
所以,我们现在更有可能处于inc eax
CISC 的时代,又名不好,而add eax,1
是 RISC ,这是好。但这些事情可能会在一夜之间发生变化。