这些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]
答案 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
)不会发生,直到它所依赖的内容完成(例如rdi
和rsi
中的值已知)。
例如,这两条指令可以并行发生(因为第二条指令并不依赖于第一条指令):
movq (%rdi), %edi
movq (%rsi), %rax
这两条指令不能并行发生(第二条指令必须等到第一条指令完成):
movq (%rdi), %rdi
movq (%rdi, %rsi), %rax
另请注意,一段代码的瓶颈可能无法执行。如果瓶颈是取指令那么更大的指令会更糟;如果瓶颈是指令解码,则更复杂的指令会更糟;如果瓶颈是数据缓存带宽,则读取/写入内存的任何内容都可能更糟糕等等。
基本上;您不能孤立地查看个别说明,并决定它们是否更好/更差。您必须查看多个指令的完整序列,以便您可以了解先前指令(及其延迟)的任何依赖性;你必须知道瓶颈是什么(例如来自绩效监测工具);如果你知道这一切,那么你可以做出一个有根据的猜测"这对于少量CPU来说真的很有用(因为不同的CPU具有不同的特性)。