x86乘法3:3:IMUL vs SHL + ADD

1 x86 assembly x86-64 intel micro-optimization

我在x86-64汇编中开发了一个程序,该程序需要通过相同的操作进行多次迭代:

IMUL rdx, 3   # rdx is always different
Run Code Online (Sandbox Code Playgroud)

但是,我需要使运行时更快,因此我从上面想到了对该特定行的优化:

MOV rcx, rdx
SHL rdx, 1
ADD rdx, rcx
Run Code Online (Sandbox Code Playgroud)

现在我问你们:这种修改会改善程序的运行时间(减少时钟),还是我应该坚持使用该IMUL命令?

Pet*_*des 6

与之相比lea rdx, [rdx + rdx*2]两者都比较糟糕,使用比例索引寻址模式获取总计*3,这就是为什么如果您要求编译器编译类似

long foo(long x){ return x * 3; }https://godbolt.org/z/6p4ynV


LEA是一种通过x86寻址模式提供任意数字的方法,无需将结果用于装载或存储,只需将其放入寄存器即可。 在不是地址/指针的值上使用LEA吗?


在所有现代x86 CPU上,LEA都是单个uop。 唯一的问题是,它比替代方案要好多少 imul也是1 uop,但前端的mov + shl + add是3。(在所有仍然相关的主流和低功耗英特尔/ AMD上都是如此。请参阅https://agner.org/optimize/)64imul在某些较旧的微体系结构(例如Bulldozer系列和Silvermont / Goldmont)上特别慢,或尤其是较旧的Atom。

在AMD CPU(Bulldozer / Ryzen)上,它具有缩放的索引,因此它是“复杂”的LEA,并且具有2个周期的延迟(imulRyzen上为3 ,而在Bulldozer系列上则更糟,后者的64位imul速度较慢且不够完整)管道)。在Ryzen上,此LEA仍具有每时钟2个吞吐量。

在Intel CPU上,它只有2个组件(一个+),因此它是一个“简单的” LEA,具有1个周期的延迟,并且可以2个时钟的吞吐量运行。 因此,与一条shl指令的成本大致相同,但运行在不同的端口上。

(或者在Ice Lake上,因为它们将LEA单元添加到其他2个整数ALU端口中,所以每4个小时一次。因此,它的价格与addIce Lake上的价格完全一样。)


你只想mov; shl; subadd当您的乘数为2 ^ n +-1时n > 3。然后值得考虑imul在延迟和前端吞吐量成本之间进行权衡。

通过移动原始寄存器,即使没有mov消除的CPU (在IvyBridge和Ryzen之前)也可以以2个周期的延迟关键路径长度运行mov / shl / add序列。


还相关:用于测试Collat​​z猜想的C ++代码比手写汇编要快-为什么?详细介绍了*3LEA与优化之间的问题。

其他相关:


归档时间:

查看次数:

161 次

最近记录:

6 年,7 月 前