7.3 ARM

7.3.1 未优化的Keil + ARM mode

  1. .text:000000A4 00 30 A0 E1 MOV R3, R0
  2. .text:000000A8 93 21 20 E0 MLA R0, R3, R1, R2
  3. .text:000000AC 1E FF 2F E1 BX LR
  4. ...
  5. .text:000000B0 main
  6. .text:000000B0 10 40 2D E9 STMFD SP!, {R4,LR}
  7. .text:000000B4 03 20 A0 E3 MOV R2, #3
  8. .text:000000B8 02 10 A0 E3 MOV R1, #2
  9. .text:000000BC 01 00 A0 E3 MOV R0, #1
  10. .text:000000C0 F7 FF FF EB BL f
  11. .text:000000C4 00 40 A0 E1 MOV R4, R0
  12. .text:000000C8 04 10 A0 E1 MOV R1, R4
  13. .text:000000CC 5A 0F 8F E2 ADR R0, aD_0 ; "%d
  14. "
  15. .text:000000D0 E3 18 00 EB BL __2printf
  16. .text:000000D4 00 00 A0 E3 MOV R0, #0
  17. .text:000000D8 10 80 BD E8 LDMFD SP!, {R4,PC}

main()函数里调用了另外两个函数,3个值被传递到f();

正如前面提到的,ARM通常使用前四个寄存器(R0-R4)传递前四个值。

f()函数使用了前三个寄存器(R0-R2)作为参数。

MLA (Multiply Accumulate)指令将R3寄存器和R1寄存器的值相乘,然后再将乘积与R2寄存器的值相加将结果存入R0,函数返回R0。

一条指令完成乘法和加法4,如果不包括SIMD新的FMA指令5,通常x86下没有这样的指令。

第一条指令MOV R3,R0,看起来冗余是因为该代码是非优化的。

BX指令返回到LR寄存器存储的地址,处理器根据状态模式从Thumb状态转换到ARM状态,或者反之。函数f()可以被ARM代码或者Thumb代码调用,如果是Thumb代码调用BX将返回到调用函数并切换到Thumb模式,或者反之。

7.3.2 Optimizing Keil + ARM mode

  1. .text:00000098 f
  2. .text:00000098 91 20 20 E0 MLA R0, R1, R0, R2
  3. .text:0000009C 1E FF 2F E1 BX LR

这里f()编译时使用完全优化模式(-O3),MOV指令被优化,现在MLA使用所有输入寄存器并将结果置入R0寄存器。

7.3.3 Optimizing Keil + thumb mode

  1. .text:0000005E 48 43 MULS R0, R1
  2. .text:00000060 80 18 ADDS R0, R0, R2
  3. .text:00000062 70 47 BX LR

Thumb模式下没有MLA指令,编译器做了两次间接处理,MULS指令使R0寄存器的值与R1寄存器的值相乘并将结果存入R0。ADDS指令将R0与R2的值相加并将结果存入R0。