Ken*_*n W 6 optimization performance assembly arm cortex-m3
在我的嵌入式系统类中,我们被要求将给定的C函数AbsVal重新编码到ARM Assembly中.我们被告知,我们能做的最好的是3行.我决心找到一个2行解决方案,并最终做到了,但我现在的问题是我是否真的降低了性能或增加了它.
C代码:
unsigned long absval(signed long x){
unsigned long int signext;
signext = (x >= 0) ? 0 : -1; //This can be done with an ASR instruction
return (x + signet) ^ signext;
}
Run Code Online (Sandbox Code Playgroud)
TA /教授的3线解决方案
ASR R1, R0, #31 ; R1 <- (x >= 0) ? 0 : -1
ADD R0, R0, R1 ; R0 <- R0 + R1
EOR R0, R0, R1 ; R0 <- R0 ^ R1
Run Code Online (Sandbox Code Playgroud)
我的2线解决方案
ADD R1, R0, R0, ASR #31 ; R1 <- x + (x >= 0) ? 0 : -1
EOR R0, R1, R0, ASR #31 ; R0 <- R1 ^ (x >= 0) ? 0 : -1
Run Code Online (Sandbox Code Playgroud)
有几个地方我可以看到潜在的性能差异:
那么,哪一个实际上更快?它取决于处理器或内存访问速度吗?
这是另一个两个指令版本:
cmp r0, #0
rsblt r0, r0, #0
Run Code Online (Sandbox Code Playgroud)
哪个转换为简单的代码:
if (r0 < 0)
{
r0 = 0-r0;
}
Run Code Online (Sandbox Code Playgroud)
该代码应该非常快,即使在像Cortex-A8和A9这样的现代ARM-CPU内核上也是如此.
访问 ARM.com 并获取Cortex-M3 数据表。第 3-4 页的 3.3.1 节包含指令时序。幸运的是,它们在 Cortex-M3 上非常简单。
从这些时间安排中我们可以看出,在完美的“无等待状态”系统中,您教授的示例需要 3 个周期:
ASR R1, R0, #31 ; 1 cycle
ADD R0, R0, R1 ; 1 cycle
EOR R0, R0, R1 ; 1 cycle
; total: 3 cycles
Run Code Online (Sandbox Code Playgroud)
你的版本需要两个周期:
ADD R1, R0, R0, ASR #31 ; 1 cycle
EOR R0, R1, R0, ASR #31 ; 1 cycle
; total: 2 cycles
Run Code Online (Sandbox Code Playgroud)
所以从理论上讲,你的速度更快。
您提到“删除一次内存获取”,但这是真的吗?各自的例程有多大?由于我们处理的是 Thumb-2,所以我们混合使用了 16 位和 32 位指令。让我们看看它们是如何组装的:
他们的版本(根据 UAL 语法进行调整):
.syntax unified
.text
.thumb
abs:
asrs r1, r0, #31
adds r0, r0, r1
eors r0, r0, r1
Run Code Online (Sandbox Code Playgroud)
组装到:
00000000 17c1 asrs r1, r0, #31
00000002 1840 adds r0, r0, r1
00000004 4048 eors r0, r1
Run Code Online (Sandbox Code Playgroud)
即 3x2 = 6 字节。
您的版本(再次根据 UAL 语法进行调整):
.syntax unified
.text
.thumb
abs:
add.w r1, r0, r0, asr #31
eor.w r0, r1, r0, asr #31
Run Code Online (Sandbox Code Playgroud)
组装到:
00000000 eb0071e0 add.w r1, r0, r0, asr #31
00000004 ea8170e0 eor.w r0, r1, r0, asr #31
Run Code Online (Sandbox Code Playgroud)
即 2x4 = 8 字节。
因此,您实际上增加了代码的大小,而不是删除内存获取。
但这会影响性能吗?我的建议是进行基准测试。