复杂的寻址模式对内存负载有额外的开销吗?

时间:2016-08-16 04:58:54

标签: performance assembly x86 micro-optimization

这些mov加载说明之间的性能是否存在差异?与简单的寻址模式相比,更复杂的寻址模式是否具有额外的开销(延迟或吞吐量)?

# AT&T syntax                       # Intel syntax:
movq (%rsi), %rax                   mov  rax, [rsi]

movq (%rdi, %rsi), %rax             mov  rax, [rdi + rsi]

movq (%rdi, %rsi, 4), %rax          mov  rax, [rdi + rsi*4]

2 个答案:

答案 0 :(得分:2)

是的,最近的Intel CPU上进行“复杂寻址”会产生开销。代价是等待时间增加了一个周期(例如,对于使用复杂寻址的普通GP负载,需要5个周期,而对于简单寻址,则需要4个周期)。

简单寻址是[reg + offset]形式的任何形式,其中offset的直接{0}到2047之间。

除了简单寻址之外,复杂寻址还

特别是任何带有两个寄存器的寻址模式,例如示例[rdi + rsi][rdi + rsi*4],都是复杂的寻址,而且会花费额外的时间。

有一种特殊情况:如果索引寄存器 1 通过调零习惯(例如xor edi, edi,但不喜欢mov edi, 0)清零,则无需支付复杂的寻址惩罚。


1 索引寄存器是一个乘以1、2、4或8的寄存器,即rsi中的[rdi + rsi*4]。如果两个寄存器都没有显示乘数,例如[rdi + rsi],则乘数为1,则您必须检查汇编程序以了解如何指定index和{ {1}}。 nasm似乎使用第二个寄存器作为索引。

答案 1 :(得分:0)

取决于具体的CPU;主要是" 不,没有额外的开销"。然而...

大多数CPU都具有无序内核,这意味着它们以最快的顺序执行指令,而不是按指令的顺序执行。为了实现这一点,一条指令(例如movq (%rdi, %rsi, 4), %rax)不会发生,直到它所依赖的内容完成(例如rdirsi中的值已知)。

例如,这两条指令可以并行发生(因为第二条指令并不依赖于第一条指令):

movq (%rdi), %edi
movq (%rsi), %rax

这两条指令不能并行发生(第二条指令必须等到第一条指令完成):

movq (%rdi), %rdi
movq (%rdi, %rsi), %rax

另请注意,一段代码的瓶颈可能无法执行。如果瓶颈是取指令那么更大的指令会更糟;如果瓶颈是指令解码,则更复杂的指令会更糟;如果瓶颈是数据缓存带宽,则读取/写入内存的任何内容都可能更糟糕等等。

基本上;您不能孤立地查看个别说明,并决定它们是否更好/更差。您必须查看多个指令的完整序列,以便您可以了解先前指令(及其延迟)的任何依赖性;你必须知道瓶颈是什么(例如来自绩效监测工具);如果你知道这一切,那么你可以做出一个有根据的猜测"这对于少量CPU来说真的很有用(因为不同的CPU具有不同的特性)。