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命令?
与之相比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/)64位imul在某些较旧的微体系结构(例如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; sub或add当您的乘数为2 ^ n +-1时n > 3。然后值得考虑imul在延迟和前端吞吐量成本之间进行权衡。
通过移动原始寄存器,即使没有mov消除的CPU (在IvyBridge和Ryzen之前)也可以以2个周期的延迟关键路径长度运行mov / shl / add序列。
还相关:用于测试Collatz猜想的C ++代码比手写汇编要快-为什么?详细介绍了*3LEA与优化之间的问题。
其他相关:
| 归档时间: |
|
| 查看次数: |
161 次 |
| 最近记录: |