Is it possible to assign specific physical register(s) to a ‘special’ global variable at the time of code generation phase in LLVM?
Details: I have a Mips-like target and following Cpu0 tutorial, I added my custom backend to LLVM. I have a global variable that I want to use in many places in the program. I define a global variable in the program like, ‘test.cpp’ - ‘int special;’
I want to assign / allocate a specific physical register in my backend to this special global variable.
Current status: Using ‘llc -debug’, I see that during the register allocation (greedy), the address of ‘special’ variable goes to a general purpose register and then it loads in a random general purpose register.
I don’t know if it is possible what I am trying to do? At which compilation stage should I try?
I read somewhere that using ‘register’ keyword is not good idea.
Thank you very much.
Excuse my English.
Sounds like "Global Named Register Variables". E.g.
clang ... -ffixed-r3 ...
register unsigned arm_r3 __asm("r3");
I know these are supported for Arm. See:
https://reviews.llvm.org/D68862 (includes test files that'll show you
how to use it from C)
I don't know whether that will "just work" for your backend (I assume
you need some option to mark the reserved register) but it should give
you a starting point.
If you want to do this with a real (programmer-visible) global, David's suggestion is exactly right.
If your global is sufficiently special, then you might instead want to look at how things like the global pointer and thread pointer are handled in different back ends. These are generally registers that are reserved but contains a value that is used in CodeGen. There are a few variants:
- Initialised somewhere else, used throughout CodeGen. The thread pointer is in this category (e.g. HWR 25 on MIPS, FS/GS base on x86). These are sometimes not even writeable in userspace and must be set by the kernel.
- Initialised by rtld stub code on cross-library calls, may or may not be preserved on cross-library calls. I believe the global pointer works like this on some PowerPC ABIs with function descriptors and on the o32 MIPS ABI.
- Set up in the function prolog but then guaranteed to be there for the rest of codegen. $gp on MIPS 'new' ABIs works like this. MIPS (prior to r6) does not have PC-relative addressing and so the ABI requires callers to use $t9 ($25) as the register that they jump to, allowing the callee to guarantee that $t9 contains the PC on function entry. It then does a fixed relocation of the distance from the function entry to the __gp variable to load the address of the GOT into $gp. Functions that are not exported or address taken may be able to optimise this setup away, if all of their callers will have set up $gp.