Performance 地址操作数如何影响机器代码的性能和大小?

Performance 地址操作数如何影响机器代码的性能和大小?,performance,optimization,assembly,x86,x86-64,Performance,Optimization,Assembly,X86,X86 64,从32位CPU模式开始,x86体系结构提供了扩展地址操作数。可以指定基址、位移、索引寄存器和比例因子 例如,我们希望遍历一个32位整数的列表(32字节长的数据结构数组中的前两个整数,%rdi作为数据索引,%rbx作为基本指针) 据我所知,这种复杂的寻址适合于单个机器代码指令。但这种操作的成本是多少?与独立指针计算的简单寻址相比,成本是多少 addl $32, %rbx # skip eight values: move pointer forward by 32 bytes movl

从32位CPU模式开始,x86体系结构提供了扩展地址操作数。可以指定基址、位移、索引寄存器和比例因子

例如,我们希望遍历一个32位整数的列表(32字节长的数据结构数组中的前两个整数,
%rdi
作为数据索引,
%rbx
作为基本指针)

据我所知,这种复杂的寻址适合于单个机器代码指令。但这种操作的成本是多少?与独立指针计算的简单寻址相比,成本是多少

addl  $32, %rbx      # skip eight values: move pointer forward by 32 bytes
movl  (%rbx), %eax   # load data: pointer
addl  $4, %rbx       # point next value: move pointer forward by 4 bytes
movl  (%rbx), %edx   # load data: pointer
在后一个示例中,我引入了一条额外的指令和一个依赖项。但整数加法非常快,我得到了更简单的地址操作数,并且不再有乘法。另一方面,由于允许的缩放因子是2的幂,因此乘法可归结为位移位,这也是一种非常快速的操作。不过,两个加法和一个位移位可以用一个加法来代替

这两种方法的性能和代码大小有什么不同?是否有使用扩展寻址操作数的最佳实践

或者,从C程序员的角度来看,什么更快:数组索引还是指针算法



是否有用于尺寸/性能调整的汇编编辑器?我希望我能看到每个汇编指令的机器代码大小、以时钟周期表示的执行时间或依赖关系图。有成千上万的装配怪胎将受益于这种应用程序,所以我打赌类似的东西已经存在

地址算法非常快,如果可能,应始终使用

但问题遗漏了一些东西

首先,你不能用地址算法乘以32——8是可能的最大常数

中代码的第一个版本不完整,因为它需要第二条指令,即递增
rbx
。因此,我们有以下两种变体:

inc  rbx          
mov  eax, [8*rbx+rdi]
vs

这样,两种变体的速度将相同。大小相同-也是6字节

因此,哪种代码更好只取决于程序上下文-如果我们有一个寄存器已经包含所需数组单元的地址-使用mov eax,[rbx]


如果我们有包含单元格索引的寄存器和另一个包含起始地址的寄存器,那么使用第一个变量。这样,在算法结束后,我们仍将在rdi中拥有数组的起始地址。

地址算法非常快,如果可能,应始终使用

但问题遗漏了一些东西

首先,你不能用地址算法乘以32——8是可能的最大常数

中代码的第一个版本不完整,因为它需要第二条指令,即递增
rbx
。因此,我们有以下两种变体:

inc  rbx          
mov  eax, [8*rbx+rdi]
vs

这样,两种变体的速度将相同。大小相同-也是6字节

因此,哪种代码更好只取决于程序上下文-如果我们有一个寄存器已经包含所需数组单元的地址-使用mov eax,[rbx]


如果我们有包含单元格索引的寄存器和另一个包含起始地址的寄存器,那么使用第一个变量。这样,在算法结束后,我们仍然可以在rdi中找到数组的起始地址。

您的问题的答案取决于给定的本地程序流情况,而这些情况又可能在处理器制造商和体系结构之间存在很大的差异。对一两条指令进行微分析通常是毫无意义的。你有一个多阶段的管道,不止一个整数单元,缓存和更多的发挥作用,你需要考虑到你的分析

您可以通过查看生成的汇编代码并分析序列相对于将在其上工作的不同硬件单元的外观,来尝试反向工程

另一种方法是使用探查器并对不同的构造进行实验,以查看哪些工作正常,哪些不正常

您还可以下载gcc的源代码,看看真正酷的程序员是如何评估一个序列以产生尽可能快的代码的。有一天你可能会成为他们中的一员:-)


在任何情况下,我希望您会得出这样的结论,即最佳序列因处理器、编译器、优化级别和周围指令的不同而有很大差异。如果您使用的是C语言,那么源代码的质量是非常重要的:垃圾输入=垃圾输出。

您的问题的答案取决于给定的本地程序流环境,而它们反过来又可能在处理器制造商和体系结构之间存在很大的差异。对一两条指令进行微分析通常是毫无意义的。你有一个多阶段的管道,不止一个整数单元,缓存和更多的发挥作用,你需要考虑到你的分析

您可以通过查看生成的汇编代码并分析序列相对于将在其上工作的不同硬件单元的外观,来尝试反向工程

另一种方法是使用探查器并对不同的构造进行实验,以查看哪些工作正常,哪些不正常

您还可以下载gcc的源代码,看看真正酷的程序员是如何评估一个序列以产生尽可能快的代码的。有一天你可能会成为他们中的一员:-)

在任何情况下,我希望您会得出这样的结论,即最佳序列因处理器、编译器、优化级别和周围指令的不同而有很大差异。如果您使用的是C语言,那么源代码的质量非常重要:垃圾输入=垃圾输出。

一般答案#0:优化是非常重要的
add  rbx, 8
mov  eax, [rbx]