3

Is it possible to reserve registers for specific part of C code?

-ffixed-reg option or declaring a global register variable is not the answer I am looking for. I want to preserve the register value for a specific scope (let's say specific function).

Using local register variable is not possible as it does not guarantee to preserve the value of register throughout the scope. I am looking for something like clobber list with asm volatile, but for C statements.

Dragonight
  • 1,033
  • 2
  • 10
  • 20
  • 1
    What you're asking for doesn't really make sense. If you want control over register allocation, write assembly language. If you want to write it in C, you won't have control over such details. – BitBank May 31 '17 at 21:24
  • I'm struggling to understand what "preserve the register value for a specific scope" might mean. Do you mean that every time the function is called, it should expect to find the previous value in that register (aka static)? Or that functions called by this function must not even USE this register (even if they restore the value when they are done)? And honestly, I can't imagine how EITHER of these scenarios could be useful. – David Wohlferd Jun 01 '17 at 01:29
  • Or maybe you have some asm at the top of a routine and some at the bottom, and you want to make sure nothing happens to the register values in between? If this is the case, show us the code, perhaps we can make some suggestions. – David Wohlferd Jun 01 '17 at 01:29
  • What I meant was that, I want to tell the compiler not to use a particular register for code generation for a segment of a code. @David Wohlferd – Dragonight Jun 01 '17 at 22:20

1 Answers1

1

GCC gives three mechansims,

  1. asm clobber
  2. Local register variable
  3. Global register variables

It is important to note that compiler register allocation is fundamental to modern optimization and reserving a register can generate worse compiled code. With the ARM mode and 16 registers (only 13 usable) you should be able to reserve one register like this for a function without too much harm. However, you should not use these facilities lightly and it would not be surprising to find some performance issues.

It sounds like the global register variable is the most applicable to you. Just have register int *foo asm ("r4"); at the start of each 'C' module that needs it.

If you have a small cluster/tree of functions, you could use a macro to reserve and contain this to one 'C' unit.

#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));
}

Knowing the use of the variable is important as there are more efficient ways (like asm clobber) to get the same effect for some variable life-times and uses. In most cases, people would just declare a parameter. Ie, it is much better to let the compiler know what you are using this for as it can make informed decision on when to spill or not.

It is difficult to think of a case where reserving a register is not misguided. An example where this might be useful is interacting with a cross language/interpreter. The above macro should work as a quick way to pass information between routines by reserving a register.

You should not use R0-R3 as you will restrict the parameters that can be passed among routines. The ARM ABI passes parameters in R0-R3. Given you have flexibility to choose a register, pick R4-R9 (possibly even R9 is off limits) as these are 'callee' saved registers without any special use. As well, if you choose R0-R3 you may NOT call standard 'C' library routines or the reserved register will be saved on the stack.

Reference: GCC local register variables
                    ARM register calling conventions

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • Maybe related, [sharing registers between threads](https://stackoverflow.com/questions/16718484/is-it-possible-to-share-a-register-between-threads) – artless noise Jun 01 '17 at 14:12
  • You can not use `R9` is you have a `static base`; which 99% of ARM code does not use. Ie, `R9` can be a 'reserved register` in some systems which is typically a shared libraries *data* section. See: [ARM static linked shared library](https://stackoverflow.com/questions/25172834/how-to-create-static-linked-shared-libraries) – artless noise Jun 01 '17 at 14:18
  • Note that this use of register-asm local variables is *not* officially supported by GCC anymore. https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html. (The only supported use is to make `"r"` constraints pick a certain reg for Extended asm. But in practice this does still work, at least for now, at least usually, with GCC. Not clang, in case that matter.) – Peter Cordes Mar 25 '21 at 02:36