当我是手写程序集时,我通常选择表单
lea eax, [eax+4]在表格上..。
add eax, 4我听说lea是一个“0时钟”指令(如NOP),而'add‘则不是。然而,当我查看编译器生成的程序集时,我经常看到后面的形式而不是第一个。我很聪明,可以信任编译器,所以谁能弄清楚哪一个更好?哪个更快?为什么编译器选择后一种形式而不是前者?
发布于 2011-06-13 09:02:27
LEA和ADD在x86 CPU上的一个显著区别是执行单元,它实际上执行指令。现代的x86 CPU是超标量的,有多个并行运行的执行单元,管道给它们提供的东西有点像循环(酒吧档)。问题是,LEA由处理寻址的单元(在流水线的早期阶段发生)处理,而ADD处理到ALU(算术/逻辑单元)和后期的流水线中。这意味着超标量x86 CPU可以同时执行LEA和算术/逻辑指令。
LEA通过地址生成逻辑而不是算术单元这一事实也是它过去被称为“零时钟”的原因;执行它不需要时间,因为地址生成在执行/执行时已经发生了。
它不是免费的,因为地址生成是执行过程中的一个步骤,但是它没有执行开销。而且它不占用ALU管道中的一个槽。
编辑:澄清,LEA是不自由的。即使在没有通过算术单元实现它的CPU上,由于指令解码/调度/退出和/或所有指令经过的其他管道阶段,执行也需要时间。对于通过地址生成实现LEA的CPU来说,执行它所花费的时间只是在管道的另一个阶段。
发布于 2011-06-12 16:44:19
--我很聪明,可以信任编译器,所以有人能说明哪一个更好吗?
是的,有点。首先,我从以下消息中获取这些信息:https://groups.google.com/group/bsdnt-devel/msg/23a48bb18571b9a6
在这条消息中,一位开发人员优化了一些我写得非常糟糕的程序集,以便在Intel 2处理器中疯狂地快速运行。作为这个项目的背景,它是一个bignum库,我和其他一些开发人员已经参与其中。
在本例中,所优化的只是添加两个类似于以下内容的数组:uint64_t* x, uint64_t* y。每个“肢体”或数组中的成员都代表大的一部分;基本的过程是从最不重要的分支开始迭代它,将对加起来并继续向上,每次传递进位(任何溢出)。adc在处理器上为您这样做(我不认为从C中访问进位标志是不可能的)。
在这段代码中,使用了lea something, [something+1]和jrcxz的组合,这显然比我们以前可能使用的jnz/add something, size组合更有效。不过,我不确定这是否是由于简单地测试不同的指令而发现的。你得问问。
然而,在稍后的消息中,它是在AMD芯片上测量的,性能不太好。
我还可以理解不同的操作在不同的处理器上执行的不同。例如,我知道GMP项目使用cpuid检测处理器,并根据不同的体系结构(如core2、nehalem )传递不同的组装例程。
您必须问自己的问题是,您的编译器是否为您的cpu架构产生优化的输出?例如,已知Intel编译器就是这样做的,因此它可能值得测量性能并查看它所产生的输出。
发布于 2011-06-12 18:08:10
LEA并不比ADD指令快,执行速度是一样的。
但是LEA sometimes offer more than ADD。如果我们需要简单而快速的加法/乘法与二次寄存器相结合,LEA可以加快程序的执行速度。另一方面,LEA不影响CPU标志,因此不存在溢出检测的可能性。。
https://stackoverflow.com/questions/6323027
复制相似问题