12.2 ARM

12.2.1 无优化 Keil + ARM模式

  1. main
  2. STMFD SP!, {R4,LR}
  3. MOV R4, #2
  4. B loc_368
  5. ; ---------------------------------------------------------------------------
  6. loc_35C ; CODE XREF: main+1C
  7. MOV R0, R4
  8. BL f
  9. ADD R4, R4, #1
  10. loc_368 ; CODE XREF: main+8
  11. CMP R4, #0xA
  12. BLT loc_35C
  13. MOV R0, #0
  14. LDMFD SP!, {R4,PC}

迭代计数器i存储到了R4寄存器中。

  1. MOV R4,#2初始化i
  2. MOV R0,R4 BL f 指令组成循环体,第一个指令为f()准备参数,第二个用来调用它。
  3. ADD R4,R4, #1 指令在每次迭代中为i加一。
  4. CMP R4,#0xA i0xA10)比较,下一个指令BLTBranch Less Than,分支小于)将在i<10时跳转。
  5. 否则, R0将会被写入0(因为我们的函数返回0),然后函数执行终止。

12.2.2 优化后的 Keil + ARM模式

  1. _main
  2. PUSH {R4,LR}
  3. MOVS R4, #2
  4. loc_132 ; CODE XREF: _main+E
  5. MOVS R0, R4
  6. BL example7_f
  7. ADDS R4, R4, #1
  8. CMP R4, #0xA
  9. BLT loc_132
  10. MOVS R0, #0
  11. POP {R4,PC}

事实上,是一样的。

12.2.3 优化后的 Xcode(LLVM) + thumb-2 模式

  1. _main
  2. PUSH {R4,R7,LR}
  3. MOVW R4, #0x1124 ; "%d
  4. "
  5. MOVS R1, #2
  6. MOVT.W R4, #0
  7. ADD R7, SP, #4
  8. ADD R4, PC
  9. MOV R0, R4
  10. BLX _printf
  11. MOV R0, R4
  12. MOVS R1, #3
  13. BLX _printf
  14. MOV R0, R4
  15. MOVS R1, #4
  16. BLX _printf
  17. MOV R0, R4
  18. MOVS R1, #5
  19. BLX _printf
  20. MOV R0, R4
  21. MOVS R1, #6
  22. BLX _printf
  23. MOV R0, R4
  24. MOVS R1, #7
  25. BLX _printf
  26. MOV R0, R4
  27. MOVS R1, #8
  28. BLX _printf
  29. MOV R0, R4
  30. MOVS R1, #9
  31. BLX _printf
  32. MOVS R0, #0
  33. POP {R4,R7,PC}

事实上,printf是在我的f()函数里调用的:

  1. void f(int i)
  2. {
  3. // do something here
  4. printf ("%d", i);
  5. };

所以,LLVM不仅仅是拆解了(unroll)循环,而且还把我的短函数f()给作为内联函数看待了,这样,它把它的函数体内插了8遍,而不是用一个循环来解决。对于我们这种简短的函数来说,编译器这样做是有可能的。