我有一个简单的 asm 代码,它加载 NEON 的 12 个四寄存器,并具有并行的成对加法指令和加载指令(以利用双发出功能)。我已经在这里验证了代码:
http://pulsar.webshaker.net/ccc/sample-d3a7fe78
正如我们所见,代码大约需要 13 个周期。但是当我在板上加载代码时,加载指令似乎每次加载都需要超过一个周期,我验证并发现 VPADAL 如上所述需要 1 个周期,但 VLD1 需要超过一个周期。这是为什么?
我已处理以下事项:
- 地址是 16 字节对齐的。
- 已在指令
vld1.64 {d0, d1} [r0,:128]! 中提供对齐提示!
- 在某些地方尝试过预加载指令
pld [r0, #192]
,但这似乎会增加周期,而不是真正减少延迟。
有人可以告诉我我做错了什么吗?为什么会出现这种延迟?
其他详细信息:
- 引用 cortex-a8
- arm-2009q1交叉编译工具链
- 汇编编码
最佳答案
您的代码执行速度比预期慢得多,因为按照当前编写的方式,它导致了管道停顿的完美 Storm 。在任何具有流水线架构的现代 CPU 上,指令可以在理想条件下在一个周期内执行。理想的条件是指令不等待内存并且不具有任何寄存器依赖性。您编写代码的方式不允许从内存读取延迟并使下一条指令依赖于读取结果。这会导致最糟糕的性能。另外,我不确定为什么要将成对添加累加到多个寄存器中。尝试这样的事情:
veor.u16 q12,q12,q12 @ clear accumulated sum
top_of_loop:
vld1.u16 {q0,q1},[r0,:128]!
vld1.u16 {q2,q3},[r0,:128]!
vpadal.u16 q12,q0
vpadal.u16 q12,q1
vpadal.u16 q12,q2
vpadal.u16 q12,q3
vld1.u16 {q0,q1},[r0,:128]!
vld1.u16 {q2,q3},[r0,:128]!
vpadal.u16 q12,q0
vpadal.u16 q12,q1
vpadal.u16 q12,q2
vpadal.u16 q12,q3
subs r1,r1,#8
bne top_of_loop
在执行添加之前尝试不同数量的加载指令。关键是您需要留出时间来进行读取,然后才能使用目标寄存器。
注意:使用 Q4-Q7 是有风险的,因为它们是非 volatile 寄存器。在 Android 上,您会在其中出现随机垃圾(尤其是 Q4)。
关于embedded - Neon VLD 消耗的周期比预期多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14869693/