为什么gcc编译f(1199)和f(1200)不同?

Clé*_*ent 14 c gcc arm micro-optimization

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

用于ARM的GCC 7.2.1编译:

extern void abc(int);
int test() { abc(1199); return 0; }
Run Code Online (Sandbox Code Playgroud)

......进入那个:

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

还有这个:

extern void abc(int);
int test() { abc(1200); return 0; }
Run Code Online (Sandbox Code Playgroud)

......进入那个:

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

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

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

Chr*_*odd 17

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

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

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