在AArch64/ARM64中进行整数运算时,使用32位W{n}寄存器与64位X{n}寄存器是否有性能差异?
例如,
add W1, W2, W3
比add X1, X2, X3
快吗? sdiv W1, W2, W3
比 sdiv X1, X2, X3
快吗?根据实现的不同,它会有所不同吗(例如 Apple M1/M2/M3 与 64 位 Qualcomm Snapdragon)?
我的直觉是使用 W{n} 时有一个较小的性能优势,但我不确定除了在紧密循环中之外它是否真的很重要。我对讨论此问题的官方 ARM 文档(如果有)感兴趣。在我目前正在编写的汇编代码中,我主要使用 X{n} 来保持一致性,但我想知道当我知道/期望数据适合 32 位时是否值得切换到 W{n}。
@PeterCordes 提供的链接和 @NateEldredge 的评论让我陷入了一些有趣的兔子洞。
tl;dr: 对于
ADD
、SUB
、LSL
等算术,使用 W{n} 与 X{n} 时没有性能差异。然而,在做udiv
/sdiv
时,有轻微的W{n}优势。根据实现(Cortex 与 M1)的不同,ldp
和 stp
的调用方式可能会产生微小的差异。
来源:
我怀疑这可能适用于大多数 AArch64 实现。
udiv
、sdiv
:W 形式的执行延迟为 5 到 12,X 形式的执行延迟为 5 到 20。madd
,msub
)没有区别,因此“纯”乘法没有区别。ldp
、ldnp
带符号立即偏移量:W 形式的吞吐量为 2,但 X 形式的吞吐量仅为 1。stp
、stnp
带符号立即偏移量:W 形式的吞吐量为 2,但 X 形式的吞吐量仅为 1。ldp W0, W1, [SP, #-16]
(没有感叹号)有惩罚,但ldp W0, W1, [SP, #-16]!
和ldp W0, W1, [SP], #16
没有!Apple 的 AArch64 实现与 Cortex 版本显着不同。这是我能找到的:
ldnp
和 stnp
没有区别。ldp
和 stp
在 W 形式中稍微更快,但对于带符号偏移量情况,它们的速度相同。ldr
和 str
也稍微更快。差异似乎比 ldp
/stp
更小。udiv
、sdiv
:W 形式的执行延迟为 7 到 8,X 形式的执行延迟为 7 到 9。mov W0, W1
必须执行,而mov X0, X1
只是内部寄存器重命名。mov
使用 W{n} 寄存器,从/到 SP 的速度稍慢。据我所知,人们唯一关心 W 形式与 X 形式的时间是在皮质上进行大量
udiv
/sdiv
时。在 M1 上,差异很小。总的来说,当差异确实存在时,差异很小,我怀疑在现实生活中的代码中根本没有多大关系。
我想到的另一种情况可能很重要,那就是实现一个带有展开的
memcpy
/ldp
的 stp
:在 Cortex 上,执行有符号偏移并且仅进行一次索引前或索引后调用可能会稍微有点更快,而在 M1 上,最好对所有 ldp
/stp
使用索引前或索引后调用。