我正在处理性能至关重要的应用程序的非常低级别的部分。
在调查生成的程序集时,我注意到以下指令:
lea eax,[edx*8+8]
我习惯在使用内存引用时看到添加内容(例如[edx + 4]),但这是我第一次看到乘法。
提前致谢。
答案 0 :(得分:11)
扩展我的评论并回答问题的其余部分......
是的,它仅限于2的权力。 (具体为2,4和8)因此不需要乘数,因为它只是一个班次。其重点是从索引变量和指针快速生成地址 - 其中数据类型是简单的2字节,4字节或8字节字。 (虽然它也经常被滥用于其他用途。)
至于所需的周期数:根据Agner Fog's tables,lea
指令在某些机器上是常量,在其他机器上是变量。
在桑迪桥上,如果它是“复杂或撕裂相对”则会有2个周期的惩罚。但它并没有说“复杂”是什么意思......所以除非你做基准测试,否则我们只能猜测。
答案 1 :(得分:8)
实际上,这不是lea
指令特有的内容。
这种类型的寻址称为Scaled Addressing Mode
。乘法是通过位移实现的,这是微不足道的:
例如,您可以使用mov
执行“缩放寻址”(请注意,这不是相同的操作,唯一的相似之处是ebx*4
表示地址乘法):< / p>
mov edx, [esi+4*ebx]
(来源:http://www.cs.virginia.edu/~evans/cs216/guides/x86.html#memory)
有关更完整的商家信息,请参阅this Intel document。表2-3显示允许缩放2,4或8。没别了。
延迟(就循环次数而言):我认为这根本不会受到影响。转换是一个连接问题,在三个可能的转换之间进行选择是1个多路复用器值得延迟的问题。
答案 2 :(得分:6)
扩展您的上一个问题:
乘法是否限制为2的幂(我会假设是这种情况)?
请注意,您得到base + scale * index
的结果,因此虽然scale
必须是1,2,4或8(x86整数数据类型的大小),但您可以得到等效的乘法通过使用与base
和index
相同的寄存器,通过一些不同的常量,例如:
lea eax, [eax*4 + eax] ; multiply by 5
编译器使用它来降低强度,例如:对于乘以100,取决于编译器选项(目标CPU模型,优化选项),您可能会得到:
lea (%edx,%edx,4),%eax ; eax = orig_edx * 5
lea (%eax,%eax,4),%eax ; eax = eax * 5 = orig_edx * 25
shl $0x2,%eax ; eax = eax * 4 = orig_edx * 100