复杂的寻址模式是否有额外的内存加载开销?
Do complex addressing modes have extra overhead for loads from memory?
这些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;主要是“不,没有额外的开销”。然而...
大多数 CPU 的核心都是无序的,这意味着它们以最快的顺序执行指令,而不是按照指令给出的顺序。为了使它起作用,一条指令(例如 movq (%rdi, %rsi, 4), %rax
)在它所依赖的事情完成之前不会发生(例如 rdi
和 rsi
中的值是已知的)。
例如,这 2 条指令可以并行发生(因为第二条指令不依赖于第一条):
movq (%rdi), %edi
movq (%rsi), %rax
并且这两条指令不能并行发生(第二条指令必须等到第一条指令完成):
movq (%rdi), %rdi
movq (%rdi, %rsi), %rax
另请注意,一段代码的瓶颈可能不是执行。如果瓶颈是取指令,那么更大的指令会更糟;如果瓶颈是指令解码,那么更复杂的指令可能更糟;如果瓶颈是数据缓存带宽,那么 reads/writes 到内存的任何东西都可能更糟,等等
基本上;您不能孤立地查看单个指令并确定它们是否 better/worse。您必须查看多个指令的完整序列,以便了解对先前指令(及其延迟)的任何依赖性;并且您必须知道瓶颈是什么(例如,来自性能监控工具);如果你知道所有这些,那么你可以制作一个仅对少数 CPU 真正有用的 "educated guess"(因为不同的 CPU 具有不同的特征)。
是的,"complex addressing" 在最近的 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的那个,即[rdi + rsi*4]
中的rsi
。如果两个寄存器都没有显示乘数,例如 [rdi + rsi]
,则乘数是 1
,您必须检查您的汇编器以查看如何指定哪个是 index
哪个是 displacement
。 nasm好像是用第二个寄存器作为索引
这些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;主要是“不,没有额外的开销”。然而...
大多数 CPU 的核心都是无序的,这意味着它们以最快的顺序执行指令,而不是按照指令给出的顺序。为了使它起作用,一条指令(例如 movq (%rdi, %rsi, 4), %rax
)在它所依赖的事情完成之前不会发生(例如 rdi
和 rsi
中的值是已知的)。
例如,这 2 条指令可以并行发生(因为第二条指令不依赖于第一条):
movq (%rdi), %edi
movq (%rsi), %rax
并且这两条指令不能并行发生(第二条指令必须等到第一条指令完成):
movq (%rdi), %rdi
movq (%rdi, %rsi), %rax
另请注意,一段代码的瓶颈可能不是执行。如果瓶颈是取指令,那么更大的指令会更糟;如果瓶颈是指令解码,那么更复杂的指令可能更糟;如果瓶颈是数据缓存带宽,那么 reads/writes 到内存的任何东西都可能更糟,等等
基本上;您不能孤立地查看单个指令并确定它们是否 better/worse。您必须查看多个指令的完整序列,以便了解对先前指令(及其延迟)的任何依赖性;并且您必须知道瓶颈是什么(例如,来自性能监控工具);如果你知道所有这些,那么你可以制作一个仅对少数 CPU 真正有用的 "educated guess"(因为不同的 CPU 具有不同的特征)。
是的,"complex addressing" 在最近的 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的那个,即[rdi + rsi*4]
中的rsi
。如果两个寄存器都没有显示乘数,例如 [rdi + rsi]
,则乘数是 1
,您必须检查您的汇编器以查看如何指定哪个是 index
哪个是 displacement
。 nasm好像是用第二个寄存器作为索引