ARM汇编循环

6
for (int i = 0; i < 10000; i++)
  a[i] = b[i] + c[i]

这个高级语言的ARM汇编是什么样子的?
编辑:我还假设A的基地址在R8中,B的基地址在R9中,C的基地址在R10中,并且A、B、C都是int数组。
非常感谢。
我尝试过:
MOV  R0, #0  ; Init r0 (i = 0)

Loop:

        a[i] = b[i] + c[i]   //How to fix this? 

        ADD  R0, R0, #1 ;Increment it

        CMP  R0, #1000 ;Check the limit

        BLE  Loop  ;Loop if not finished

你可能需要澄清你在这里询问的问题 - ARM风格汇编和Android编程是两个完全不同的东西; Android是像Java一样的虚拟机环境; 你不能使用汇编语言,因为代码由运行时解释,而不是直接在处理器上运行。 - Russ Clarke
关于您的编辑:您在哪个软件/设备中尝试了那个ASM? - Russ Clarke
这并不一定是针对Android的。我只是想获得在移动设备上运行的ARM汇编的经验。 - CyberShot
4个回答

8
假设这种高级语言与C没有冲突,你可以使用arm C编译器从你的代码片段创建汇编代码。例如,如果你在test.c中有以下内容:
void test() {
        register int i asm("r0");
        register int *a asm("r8");
        register int *b asm("r9");
        register int *c asm("r10");

        for (i = 0; i < 10000; i++) {
                a[i] = b[i] + c[i];
        }
}

你可以运行。
arm-linux-androideabi-gcc -O0 -S test.c

要创建一个test.s文件,其中包含您的测试函数的汇编代码以及一些额外内容。您可以在下面看到您的循环如何编译成汇编语言。

<snipped>
.L3:
        mov     r2, r8
        mov     r3, r0
        mov     r3, r3, asl #2
        add     r3, r2, r3
        mov     r1, r9
        mov     r2, r0
        mov     r2, r2, asl #2
        add     r2, r1, r2
        ldr     r1, [r2, #0]
        mov     ip, sl
        mov     r2, r0
        mov     r2, r2, asl #2
        add     r2, ip, r2
        ldr     r2, [r2, #0]
        add     r2, r1, r2
        str     r2, [r3, #0]
        mov     r3, r0
        add     r3, r3, #1
        mov     r0, r3
.L2:
        mov     r2, r0
        ldr     r3, .L5
        cmp     r2, r3
        ble     .L3
        sub     sp, fp, #12
        ldmfd   sp!, {r8, r9, sl, fp}
        bx      lr
<snipped>

现在这种方法的问题在于信任编译器生成最优代码,但并不总是如此。但你会得到快速的答案,而不必等待别人的回答 :)
-- 额外信息 --
GCC允许将变量放入特定寄存器中,请参见相关文档
你可以在这里获得ARM指令速查表。
较新版本的GCC会生成更好的ARM代码,正如人们所期望的那样。上面的片段是由版本4.4.3生成的,我可以证实Linaro的4.7.1证实了我的说法。因此,如果你采用我的方法,请使用你能够获得的最新工具链。

4

http://www.peter-cockerell.net/aalp/html/ch-5.html

;Print characters 32..126 using a FOR loop-type construct

;R0 holds the character
MOV  R0, #32  ;Init the character
.loop
SWI  WriteC  ;Print it
ADD  R0, R0, #1 ;Increment it
CMP  R0, #126 ;Check the limit
BLE  loop  ;Loop if not finished
;

1
需要一些谨慎;这个源代码来自于1987年的一本书;很有可能不适用于2012年基于ARM的Android设备。 - Russ Clarke

1
for (int i = 0; i < 10000; i++)
  a[i] = b[i] + c[i]



mov r0,#0x2700
orr r0,#0x0010
top:
ldr r1,[r9],#4
ldr r2,[r10],#4
add r1,r1,r2
str r1,[r8],#4
subs r0,#1
bne top

1
建立在 @alpera 的回答之上 - 你也可以展开循环以一次执行4个操作 - 不过是否获得性能提升取决于内存访问还是分支周围的流水线停顿哪个影响更大。
mov r11,#0x2700
orr r11,#0x0010
top:
ldmia r9!, {r0-r3}
ldmia r10!, {r4-r7}
add r0,r0,r4
add r1,r1,r5
add r2,r2,r6
add r3,r3,r7
stmia r8!, {r0-r3}
subs r11,#4
bne top

如果您有NEON单元可用,我们也可以这样做 - 在这种情况下,它将并行化负载、存储和加法 - 实际上将问题减少到执行两次循环迭代的5条指令。
C编译器默认不会生成如此紧密的代码(或者为NEON并行化),因为它必须假设用于读取和写入的缓冲区(r8、r10和r11)可能重叠 - 因此通过r8的写入可能会立即在下一次迭代中通过r9或r10进行读取。您可以使用“restrict”(在C++中为“__restrict”)修饰符告诉编译器这不是这种情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接