How to Inform Gcc to Not Use a Particular Register

GCC: Prohibit use of some registers

When writing GCC inline assembler, you can specify a "clobber list" - a list of registers that may be overwritten by your inline assembler code. GCC will then do whatever is needed to save and restore data in those registers (or avoid their use in the first place) over the course of the inline asm segment. You can also bind input or output registers to C variables.

For example:

inline unsigned long addone(unsigned long v)
{
unsigned long rv;
asm("mov $1, %%eax;"
"mov %0, %%ebx;"
"add %%eax, %%ebx"
: /* outputs */ "b" (rv)
: /* inputs */ "g" (v) /* select unused general purpose reg into %0 */
: /* clobbers */ "eax"
);
}

For more information, see the GCC-Inline-Asm-HOWTO.

Can gcc/g++ tell me when it ignores my register?

You can fairly assume that GCC ignores the register keyword except perhaps at -O0. However, it shouldn't make a difference one way or another, and if you are in such depth, you should already be reading the assembly code.

Here is an informative thread on this topic: http://gcc.gnu.org/ml/gcc/2010-05/msg00098.html . Back in the old days, register indeed helped compilers to allocate a variable into registers, but today register allocation can be accomplished optimally, automatically, without hints. The keyword does continue to serve two purposes in C:

  1. In C, it prevents you from taking the address of a variable. Since registers don't have addresses, this restriction can help a simple C compiler. (Simple C++ compilers don't exist.)
  2. A register object cannot be declared restrict. Because restrict pertains to addresses, their intersection is pointless. (C++ does not yet have restrict, and anyway, this rule is a bit trivial.)

For C++, the keyword has been deprecated since C++11 and proposed for removal from the standard revision scheduled for 2017.

Some compilers have used register on parameter declarations to determine the calling convention of functions, with the ABI allowing mixed stack- and register-based parameters. This seems to be nonconforming, it tends to occur with extended syntax like register("A1"), and I don't know whether any such compiler is still in use.

Forcing the compiler to use a certain register for a certain variable

gcc can do it.

The already cited gcc docs answers your question of how to force a variable into a certain register.

To stop the compiler from generating code using this register for other purposes, use the gcc switch -ffixed-reg (see gcc doc for details).

Reserve registers for a specific part of code using GCC compiler

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

Is it possible to use explicit register variables in GCC with C++17?

This looks like a GCC bug to me. The C++17 warning is a red herring. The code works fine with optimization for me (when compiled with GCC 7), but it breaks at -O0.

According to the documentation for local register variables, this is not expected, so this is likely a GCC bug. According to this bug report, it is not even related to optimization, but ultimately caused by the use of a template.

I suggest to overload only on the number of system call arguments in the ultimate system call wrapper, and use long types for all arguments and the result:

inline long syscall_base(long num, long arg1)
{
register long _num __asm__(_syscallNumReg) = num;
register long _arg1 __asm__(_syscallReg1) = arg1;
register long _ret __asm__(_syscallRetReg);
__asm__ __volatile__(_syscallOper
: "=r"(_ret)
: "r"(_num), "r"(_arg1)
: _syscallClob);
return _ret;
}

template <typename Ret = long, typename T1>
Ret syscall(long num, T1 arg1)
{
return (Ret) (syscall_base(num, (long) arg1));
}

You'll have to use something nicer for the casts (probably type-indexed conversion functions), and of course you still have to deal with the syscall ABI variance in some other way (x32 has long long instead of long, and POWER has two return registers instead of one, etc.), but that's also a problem with your original approach.

Is it possible to tell clang which registers to use for certain parts of the code without using assembly

rsi cannot be used for your own purpose on linux because it is used in the function calling convention psABI-x86_64

But if you can use an other register as r10 code compiled with Gcc and option -ffixed-r10 will not use r10 (demo).

How to insist a C compiler put local variables on the stack, not in registers

I suppose that you use a kind of "mark and sweep" GC. In such case you only need to save registers at the moment when marking phase starts. My advise is to examine your GC, find the place where the "mark and sweep" operation starts and to put a code placing all registers into an accessible memory here. setjmp is a semi-portable way to achieve this (unless you are working on sparc).



Related Topics



Leave a reply



Submit