ARM 程序集中分支上的延迟结果指令会发生啥情况?
Posted
技术标签:
【中文标题】ARM 程序集中分支上的延迟结果指令会发生啥情况?【英文标题】:What happens with delayed result instructions on branch in ARM assembly?ARM 程序集中分支上的延迟结果指令会发生什么情况? 【发布时间】:2012-03-23 14:17:58 【问题描述】:我正在优化 ARM 汇编中的算法,需要弄清楚指令的放置顺序以最大限度地减少流水线停顿。 http://pulsar.webshaker.net/ccc/index.php?lng=us 的循环计数器在这方面非常有用,但对函数调用/分支发生的情况缺乏了解。我想做的基本上是(这只是一个例子):
mul r4, r0, r1
mov r0, #0
mov r1, #12
mov r4, r4, ASR #14
str r4, [r5]
bl foo
mul
和mov
指令之间的流水线停顿非常可怕,没有什么能阻止我在它们之间进行函数调用。但是当我做分支时,管道到底发生了什么?我知道foo
将执行push r4-r12, lr
作为第一条指令。我可以看到两种可能的结果:
-
分支指令需要几个周期,这使得
mul
指令能够在执行push
之前传递其结果,从而减少流水线停顿。
由于push
在执行之前需要r4
几个周期,因此管道停顿增加了(ARMv7 IIRC 之前就是这种情况,链接中的周期计数器似乎认为不需要这样做)。李>
简而言之:
当您执行函数调用(假定将寄存器压入堆栈)甚至是正常分支时,结果延迟的指令(mul
是主要示例)会发生什么情况?
【问题讨论】:
只有当您尝试使用未准备好的寄存器时,您才会遇到流水线停顿。这就是流水线的重点——即使之前的结果还没有准备好,指令也会继续执行。 是的,我知道,这就是问题的重点。在执行mov r4, r4, ASR #14
时,r4
尚未准备好。即使函数将相关寄存器推入堆栈,我是否会通过在 mov
指令之前执行函数调用来减少管道停顿?
你为什么认为 mov 会出现管道停顿?乘法指令应该只需要 1 或 2 个额外时钟,具体取决于 ARM 内核的版本。如果由于某种原因,r4 需要超过 2 个时钟才能准备好,则 BL 会给它更多时间。
我认为你需要计时。不要在上一代和下一代、管道之间做任何假设,一切都可能完全不同。 Michael Abrash,汇编语言的 Zen,使用过的副本很容易获得。主题之一是,无论您认为自己对正在发生的事情有多了解,您仍然需要对其进行计时、实验和验证。另外,尝试一些疯狂的事情并计时,并弄清楚为什么应该很慢的答案要快得多。您需要在所有缓存关闭、i 缓存开启和 i/d 开启、mmu 开启和关闭等情况下进行计时(以找到不会有一个具体答案)
@BitBank: 像mul
和ldr
这样的指令如果你事后不尝试直接使用结果,只需要一两个周期。即使指令看起来已经完成,尝试使用结果直到几个时钟周期后会导致流水线停顿(这就是为什么要交错独立指令的原因)。阅读参考手册中的时间或检查计算器,你会明白我在说什么。如果以最佳方式交错指令,性能可以大大提高。
【参考方案1】:
如果我理解你不需要执行
mov r4, r4, ASR #14
str r4, [r5]
在通话之前。 在 mov 之前进行调用
bl foo
mov r4, r4, ASR #14
str r4, [r5]
是个好主意。
通话期间 mul 将有更多时间完成。 STM 将是一个显而易见的问题。当然你可以在计算之前推送 R4。
如果 foo 是一个 asm 函数,你可以稍后在 foo 函数中保存 R4(可能你可以尝试不使用 r4 然后不保存它)。
如果 foo 函数是 C 函数(或者如果您可以更改 push 指令)。使用 r12 而不是 r4 作为 MUL 的目标寄存器。
STM 指令稍后将需要 R12。那么在 STM 需要目标寄存器(R12)之前,mul 可能有足够的时间完成!
【讨论】:
【参考方案2】:我不确定答案是什么,但我很确定如果答案是公开的,那么它会在Cortex-A8 Technical Reference Manual 中。
【讨论】:
以上是关于ARM 程序集中分支上的延迟结果指令会发生啥情况?的主要内容,如果未能解决你的问题,请参考以下文章