为什么INC和ADD 1的性能不同?

12

多年来,我读到许多次应该执行 XOR ax,ax 的建议,因为它更快...或者在使用 C 编程时使用 counter++ 或 counter+=1,因为它们会 INC 或 ADD...或者在 Netburst Pentium 4 中,INC 操作比 ADD 1 更慢,所以编译器必须被警告你的目标是 Netburst,这样它才会将所有 var++ 转换为 ADD 1。

我的问题是:为什么 INC 和 ADD 的性能不同?例如,为什么 INC 在 Netburst 上被认为比其他处理器上的 ADD 更慢?


我认为这个问题只与x86架构有关。 - Ira Baxter
我不知道有哪些微架构本身上inc更快。我唯一能想到的优势可能是更小的尺寸。顺便说一下,x++x+=1并不一定分别对应于incadd,除非是在超级烂的编译器中。 - harold
在x86架构中,由于指令编码长度可变,有时候一个指令比另一个更优。如果较短的指令可以适应缓存行或解码块而较长的不能,则较短的指令会更好。如果较短的指令会将下一条指令的一半留在当前窗口,另一半留在下一个窗口中,则通过对其后继者进行良好的对齐,较长的指令可能更好。 - Phil Miller
@Lưu Vĩnh Phúc请看问题日期,我的问题比您链接的那个更早,它不可能是重复的(除非您相信我可以穿越时空)。 - speeder
@speeder "一般规则是保留答案最佳的问题,并将另一个问题作为重复关闭",时间在这里并不重要。大量2010年的问题被更好的2016年的问题所取代而关闭。 - phuclv
2个回答

18

对于 x86 架构,INC 只更新一部分条件码,而 ADD 则更新所有条件码。(其他架构具有不同的规则,因此这个讨论可能适用或不适用)。

因此,INC 指令必须等待更新条件码位的先前指令完成,然后才能修改该先前值以产生其最终的条件码结果。

ADD 可以在不考虑条件码的先前值的情况下生成最终的条件码位,因此它不需要等待先前的指令完成计算它们的条件码值。

结果是:您可以将 ADD 与大量其他指令并行执行,而 INC 只能与较少的其他指令并行执行。因此,ADD 在实践中似乎更快。

(我认为在处理全宽寄存器(例如 EAX)的情况下,使用 8 位寄存器(例如 AL)也存在类似问题,即 AL 更新需要先前的 EAX 更新完成。)

我不再在我的高性能汇编代码中使用 INC 或 DEC 。如果您对执行时间不太敏感,那么 INC 或 DEC 就可以正常使用,并且可以减小指令流的大小。


这听起来很有趣。您 知道 EFLAGS问题是否会导致INC的微架构延迟,还是这只是一种推测?我想知道是否有一些推测性的方法可以处理EFLAGS,以消除INC/DEC的大部分延迟。 - srking
1
@srking 很多微体系结构将EFLAGS拆分成各个部分以避免假依赖。当这些部分需要重新组合时(例如使用进位标志与某些其他标志的跳转),仍会发生停顿。 - harold
我不知道处理器有多聪明,但那些工程师们有很多晶体管可以玩耍。一个有趣的观察:如果一个INC指令后面跟着一个ADD,那么INC的条件码就不再有意义了,并且INC对先前CC值的依赖在技术上也不再需要。因此,在INC之后跟随一些破坏整个CC位集的东西可能会加速它 :-} 在计算之后放置优化代码真的很奇怪! - Ira Baxter
AL/AX/EAX分区寄存器问题是为什么大多数x64指令会将32位寄存器的上半部分清零的原因。 - phuclv
看起来是一个相当不错的更新。我很高兴我的答案现在正式过时和不正确了。谢谢,彼得。 - Ira Baxter
显示剩余2条评论

4
XOR ax, ax的位操作已经过时了,现在使用赋值为零来代替它。
关于C语言中的counter++counter+=1的比较也已经过时了,应该使用后者。
之所以在汇编语言中使用XOR ax, ax,是因为所有指令都会被转换成CPU的某种操作,而设计人员总是尽可能地使所有操作更快。INC操作只需处理一个寄存器,因此可能更快,但这是极度简化的说法。
然而,在C语言中,如果INC比ADD更快,那么编译器设计人员为什么不使用INC来代替ADD,无论是在counter++还是counter+=1中?编译器进行了很多优化,这种改变并不复杂。

7
实际上,“xor”技巧现在甚至更加优秀。在SandyBridge上,它由寄存器重命名器处理——它甚至不再进入任何执行单元。 - harold
@harold sweet。又一个让我感到高兴的原因是,编译器的开发人员比我知道更多;) - Jon Hanna
@harold Sandy Bridge 甚至对于 sub X,X 这种特殊情况也有优化。不确定为什么会需要这样做,因为所有合理的编译器已经使用 xor X,X 了。 - Mysticial
@Mysticial 这有点颠倒了吧,如果他们只专注于编译器当前使用的东西,那么现代技术的进步不会受到限制吗? - Jon Hanna
1
@Mysticial,理智的编译器做什么并不特别重要,Intel花费了大量时间尝试让20年前使用糟糕编译器编译的Fortran/Cobol/Assembly代码运行得更快。在许多情况下,源代码已经无法找到,或者生成可执行文件的工具链已经不存在了。 - Danny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接