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

标签 c gcc arm micro-optimization

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

GCC 7.2.1 for 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 会使用从内存加载来获取常量,而不是使用立即数?

最佳答案

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

常量1200在二进制中是10010110000,所以它可以编码为8位常量01001011加上循环4。

常量 1199 在二进制中是 10010101111,因此无法将其放入 ARM 常量操作数。

关于c - 为什么 gcc 以不同的方式编译 f(1199) 和 f(1200)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48573590/

相关文章:

linux - libelf 破坏 ARM elf 二进制文件

打不开C图

c - 错误 : expected ')' before ';' token

c - 在 C 中使用 enum 和 int 变量的区别

linux - arm linux 系统调用中 vector_swi() 中使用的堆栈指针是如何初始化的?

c++ - 在 Linux 上从 UART 进行阻塞 read()

c - 如何在不触及先前写入的情况下写入 C 中的数据寄存器?

c - 以 ascii 形式打印十六进制数组

gcc - gentoo系统中的多版本gcc管理

linux - 我可以在 Debian/Linux 上安装两个版本的 GCC 吗?