x86 inc与add指令的相对性能

Pre*_*zer 9 optimization performance x86 assembly

快速提问,事先假设

mov eax, 0
Run Code Online (Sandbox Code Playgroud)

哪个更有效率?

inc eax
inc eax
Run Code Online (Sandbox Code Playgroud)

要么

add eax, 2
Run Code Online (Sandbox Code Playgroud)

另外,如果两个incs更快,编译器(比方说,GCC)通常(即没有积极的优化标志)是否优化var += 2呢?

谢谢你的时间!

PS:不要费心回答"不要过早优化",这仅仅是学术兴趣.

Gun*_*iez 18

inc同一寄存器上的两条指令(或更一般地说,两条读 - 修改 - 写指令)总是具有至少两个周期的依赖链.这假设一个inc的一个时钟延迟,这是自486以来的情况.这意味着如果周围的指令不能与两个inc指令交错以隐藏那些延迟,则代码将执行得更慢.

但是没有编译器会发出你提出的指令序列(mov eax,0将替换为xor eax,eax,看看寄存器与自身进行异或的目的是什么?)

mov eax,0
inc eax
inc eax
Run Code Online (Sandbox Code Playgroud)

它会被优化

mov eax,2
Run Code Online (Sandbox Code Playgroud)

  • 请注意`xor eax, eax; 不过,大多数编译器都比“mov eax, 1”更喜欢 inc eax。可能是因为它是 3 个字节而不是 5 个字节。 (2认同)

Nec*_*lis 12

如果您想知道x86指令的原始性能统计数据,请参阅Agner Fogs博士列表(确切地说是第4卷).关于编译器的部分,那依赖于编译器的代码生成器,而不是你应该依赖的东西.

在旁注:我觉得有趣/具有讽刺意味的是,在关于性能的问题中,你习惯于MOV EAX,0将寄存器归零而不是XOR EAX,EAX:P(如果MOV EAX,0事先完成,最快的变体就是删除inc并添加'和' MOV EAX,2).


kar*_*lip 2

出于所有目的,这可能并不重要。但请考虑到inc使用较少的字节。

考虑以下代码:

int x = 0;
x += 2;
Run Code Online (Sandbox Code Playgroud)

在不使用任何优化标志的情况下,GCC将此代码编译为:

80483ed:       c7 44 24 1c 00 00 00    movl   $0x0,0x1c(%esp)
80483f4:       00 
80483f5:       83 44 24 1c 02          addl   $0x2,0x1c(%esp)
Run Code Online (Sandbox Code Playgroud)

使用-O1-O2,它变成:

c7 44 24 08 02 00 00    movl   $0x2,0x8(%esp)
Run Code Online (Sandbox Code Playgroud)

很有趣,不是吗?