【问题标题】:Reserve registers for a specific part of code using GCC compiler使用 GCC 编译器为代码的特定部分保留寄存器
【发布时间】:2017-05-31 20:19:44
【问题描述】:

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

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

使用本地寄存器变量是不可能的,因为它不能保证在整个范围内保留寄存器的值。 我正在寻找带有 asm volatile 的 clobber list 之类的东西,但是对于 C 语句。

【问题讨论】:

  • 你所要求的并不真正有意义。如果要控制寄存器分配,请编写汇编语言。如果你想用 C 来写,你将无法控制这些细节。
  • 我很难理解“为特定范围保留寄存器值”可能意味着什么。您的意思是每次调用该函数时,它都应该期望在该寄存器中找到以前的值(又名静态)?或者这个函数调用的函数甚至不能使用这个寄存器(即使它们在完成后恢复值)?老实说,我无法想象这些场景中的任何一个会有什么用处。
  • 或者你在例程的顶部有一些 asm,在底部有一些,你想确保中间的寄存器值没有发生任何变化?如果是这样的话,给我们看看代码,也许我们可以提出一些建议。
  • 我的意思是,我想告诉编译器不要使用特定寄存器来生成代码段的代码。 @大卫沃尔弗德

标签: gcc arm register-allocation


【解决方案1】:

GCC 给出了三种机制,

  1. asmclobber
  2. Local register variable
  3. Global register variables

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

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

如果您有一个小的功能集群/树,您可以使用宏来保留并将其包含到一个“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)可以对某些变量的生命周期和使用获得相同的效果。在大多数情况下,人们只会声明一个参数。即,最好让编译器知道您使用它的目的,因为它可以就何时溢出或不溢出做出明智的决定。

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

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

参考: GCC local register variables
                    ARM register calling conventions

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
  • 1970-01-01
  • 2017-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多