为什么gcc编译f(1199)和f(1200)会有不同的结果?

14

什么导致GCC 7.2.1在ARM上对于某些常量使用从内存(lr)加载,而在其他一些情况下使用立即数(mov)?具体来说,我看到以下内容:

GCC 7.2.1适用于ARM编译了这个:

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个回答

17

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

常量 1200 的二进制表示为 10010110000,因此它可以被编码为8位常量01001011和旋转4。

常量 1199 的二进制表示为 10010101111,所以无法将其装入ARM常量操作数中。


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