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

时间:2017-05-31 20:19:45

标签: gcc arm register-allocation

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

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

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

1 个答案:

答案 0 :(得分:0)

GCC给出了三个机制,

  1. asm clobber
  2. Local register variable
  3. Global register variables
  4. 重要的是要注意编译器寄存器分配是现代优化的基础,保留寄存器可以生成更糟糕的编译代码。使用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,您可以 NOT 调用标准的'C'库例程,否则保留的寄存器将保存在堆栈中。

    参考: GCC local register variables
    ARM register calling conventions