使用 GCC 编译器为代码的特定部分保留寄存器

Reserve registers for a specific part of code using GCC compiler

是否可以为C代码的特定部分保留寄存器?

-ffixed-reg 选项或声明全局寄存器变量不是我要找的答案。我想保留特定范围的寄存器值(比方说特定功能)。

无法使用局部寄存器变量,因为它不能保证在整个范围内保留寄存器的值。 我正在寻找类似带有 asm volatile 的 clobber list 的东西,但用于 C 语句。

GCC给出了三种机制,

  1. asm 破坏
  2. Local register variable
  3. Global register variables

重要的是要注意编译器寄存器分配是现代优化的基础,保留寄存器会生成更糟糕的编译代码。使用 ARM 模式和 16 个寄存器(只有 13 个可用),您应该能够像这样为一个函数保留一个寄存器而不会造成太大伤害。但是,您不应轻易使用这些工具,发现一些性能问题也就不足为奇了。

听起来全局寄存器变量最适合你。只需在每个需要它的 'C' 模块的开头添加 register int *foo asm ("r4");

如果您有一小部分 cluster/tree 函数,您可以使用宏来保留并将其包含在一个 'C' 单元中。

#define RESERVE_REG(reg)  register int RR_##reg asm (#reg) \
                                 __attribute__((unused))

int bar(int a) { 
  RESERVE_REG(R4); 
  int b; 
  b += CRAZY_ASM(a); 
  return b;
}
void foo(void) { 
 RESERVE_REG(R4); 
 CRAZY_ASM_SET_R4(82);
 printf("value is %d\n", bar(1));
}

了解变量的使用很重要,因为有更有效的方法(如 asm clobber)可以为某些变量的生命周期和使用获得相同的效果。在大多数情况下,人们只会声明一个参数。也就是说,最好让编译器知道您正在使用它做什么,因为它可以就何时溢出或不溢出做出明智的决定。

很难想象保留寄存器不被误导的情况。这可能有用的一个例子是与十字 language/interpreter 交互。上面的宏应该作为一种通过保留寄存器在例程之间传递信息的快速方法。

您不应使用 R0-R3,因为您将限制可以在例程之间传递的参数。 ARM ABI 在 R0-R3 中传递参数。如果您可以灵活地选择寄存器,请选择 R4-R9(甚至 R9 也可能是禁区),因为这些是 'callee' 保存的寄存器,没有任何特殊用途。同样,如果您选择 R0-R3,您可以 NOT 调用标准 'C' 库例程,否则保留的寄存器将保存在堆栈中。

参考: GCC local register variables
ARM register calling conventions