为什么gcc以不同的方式编译f(1199)和f(1200)?

时间:2018-02-01 23:46:01

标签: c gcc arm micro-optimization

什么原因导致ARM上的GCC 7.2.1对内存(lr)使用某些常量的负载,以及在某些其他情况下立即使用(mov)?具体来说,我看到以下内容:

ARM的GCC 7.2.1编译:

extern void abc(int);
int test() { abc(1199); return 0; }

......进入那个:

test():
  push {r4, lr}
  ldr r0, .L4  // ??!
  bl abc(int)
  mov r0, #0
  pop {r4, lr}
  bx lr
.L4:
  .word 1199

和此:

extern void abc(int);
int test() { abc(1200); return 0; }

......进入那个:

test():
  push {r4, lr}
  mov r0, #1200  // OK
  bl abc(int)
  mov r0, #0
  pop {r4, lr}
  bx lr

起初我预计1200会成为某种独特的截止,但在1024处还有其他类似的截止(1024产生mov r0, #1024,而1025使用ldr)和其他值

为什么GCC会使用内存加载来获取常量,而不是使用立即?

1 个答案:

答案 0 :(得分:17)

这与在ARM指令集中编码常量操作数的方式有关。它们被编码为(无符号)8位常数和4位旋转字段 - 8位值将旋转该4位字段中值的2倍。因此,适合该形式的任何值都可以用作常量参数。

常量1200是二进制的10010110000,因此它可以编码为8位常数0100​​1011和4的旋转。

常量1199是二进制的10010101111,因此无法将其置于ARM常量操作数中。