5
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
4

4 回答 4

7

假设这种高级语言与 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 证明了我的主张。因此,如果您采用我的方法,请使用您可以获得的最新工具链。

于 2012-08-16T06:50:38.820 回答
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
;
于 2012-08-16T02:18:35.107 回答
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
于 2012-08-16T03:48:58.823 回答
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 条指令,一次执行两次循环迭代。

AC 编译器默认不会生成如此紧密的代码(或 NEON 的并行化),因为它必须假设用于读取和写入的缓冲区(r8、r10 和 r11)可能会重叠 - 因此通过 r8 的写入可能会立即被读入通过 r9 或 r10 循环的下一次迭代。您可以使用restrict(__restrict在 C++ 中) 修饰符告诉编译器情况并非如此。

于 2012-08-16T09:15:57.583 回答