复杂的寻址模式是否有额外的内存负载开销



这些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]

是的,在最近的英特尔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相乘的寄存器,即[rdi + rsi*4]中的rsi。在这种情况下,两个寄存器都没有显示乘数,比如[rdi + rsi],乘数是1,您必须检查汇编程序,看看如何指定哪个是index,哪个是displacement。Nasm似乎使用第二个寄存器作为索引。

取决于具体是哪个CPU;大多数情况下"不,没有额外的开销"。然而…

大多数cpu都有乱序内核,这意味着它们以最快的顺序执行指令,而不是按照给定的顺序执行指令。为了使其工作,一条指令(例如movq (%rdi, %rsi, 4), %rax)不能发生,直到它所依赖的事情完成(例如rdirsi中的值是已知的)。

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

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

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

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

还要注意,一段代码的瓶颈可能不是执行。如果瓶颈是指令提取,那么较大的指令会更糟糕;如果瓶颈是指令解码,那么更复杂的指令可能会更糟糕;如果瓶颈是数据缓存带宽,那么任何读/写内存的事情都可能更糟糕,等等。

基本上

;你不能孤立地看单个指令,然后决定它们是更好还是更差。你必须查看多个指令的整个序列,这样你才能知道之前指令的依赖关系(以及它们的延迟);你必须知道瓶颈是什么(例如,从性能监控工具);如果你知道所有这些,那么你可以做出一个"有根据的猜测",这只对少数cpu有用(因为不同的cpu有不同的特性)。

最新更新