我需要减少Cortex-M0微处理器的代码膨胀。
启动时,必须将ROM数据复制到RAM数据一次。因此我有这段代码:
void __startup( void ){
extern unsigned int __data_init_start;
extern unsigned int __data_start;
extern unsigned int __data_end;
// copy .data section from flash to ram
s = & __data_init_start;
d = & __data_start;
e = & __data_end;
while( d != e ){
*d++ = *s++;
}
}
编译器生成的汇编代码如下所示:
ldr r1, .L10+8
ldr r2, .L10+12
sub r0, r1, r2
lsr r3, r0, #2
add r3, r3, #1
lsl r1, r3, #2
mov r3, #0
.L4:
add r3, r3, #4
cmp r3, r1
beq .L9
.L5:
ldr r4, .L10+16
add r0, r2, r3
add r4, r3, r4
sub r4, r4, #4
ldr r4, [r4]
sub r0, r0, #4
str r4, [r0]
b .L4
如何优化此代码以使代码大小最小?
答案 0 :(得分:1)
编译器(或您!)没有意识到要复制的范围是end - start
。似乎有一些不必要的数据正在进行 - 循环中的2 add
和sub
。此外,在我看来,编译器确保要制作的副本数是4的倍数。然后,显而易见的优化是以确保它是提前的!下面我假设它是(如果没有,bne
将会失败,并愉快地继续复制和践踏你的记忆。)
使用我十年前的ARM汇编程序knowlegde(是的,这是一个主要的免责声明),以及后递增,我认为以下简短的代码段是它可以被浓缩的内容。从18指令下降到8,还不错。如果有效。
ldr r1, __data_init_start
ldr r2, __data_start
ldr r3, __data_end
sub r4, r3, r2
.L1:
ldr r3, [r1], #4 ; safe to re-use r3 here
str r3, [r2], #4
subs r4, r4, #4
bne L1
答案 1 :(得分:1)
可能该平台保证写入unsigned int *
您可以更改unsigned int *
值(即它不会利用类型不匹配别名规则)。
然后代码效率低下,因为e
是一个全局变量,生成的代码逻辑必须考虑到写入*d
可能会改变e
的值。
至少使e
本地化可以解决这个问题(大多数编译器都知道,从C的角度来看,从不使用其地址的本地别名是不可能的。)