Explicit register usage in LLVM assembly

Hello!
     Is there a way to force explicit register usage (e.g. %r15 in amd64 architecture) in
LLVM assembly code? I was proposed in #llvm channel at irc.oftc.net to use inline
assembly but i find it rather impractical in my case. Is there any other way?

Thanx,
~y.

Hello Yiannis,

You could write a custom backend that doesn't allocate %r15 for general usage.
The normal way to do this is to set up a custom calling convention for all
functions that keeps a sentinel in %r15 so that it always holds the sentinel.
This is how new operating systems are supported with custom ABIs. The only
problem is that you cannot be assured that %r15 stays put between function calls
such as for an interrupt.

If you had asked "Is there another EASY way to force explicit register usage?"
the answer would have been "No."

--Sam Crow

Hello Sam,
  I am not sure i made myself clear about what i want. I was wondering
if there
is a way to communicate to LLVM's register allocator and define which
registers are pre-coloured and should not be used for allocation.

~y.

Hello Yiannis,

The answer to your question is "no" or at least "not without getting your hands
really, really dirty". The intermediate representation of code is entirely
processor agnostic or tries to be. Specifying something specific to just one
processor is made impossible on purpose to prevent people from making
system-specific code that would only work on one LLVM Backend. If you want your
AMD64 processor to generate different code, you'll have to modify the AMD64
backend of LLVM and give %r15 a different register classification. Doing this
will probably require some proficiency with TableGen (which I'm not so familiar
with yet) and require that changes be made to all of the other processor
specifications as well that you plan on using with your compiler. This would
probably require a fork of the LLVM project altogether and should not be
considered lightly.

The reason I brought up about ABIs of operating systems earlier is that that is
the only time LLVM knows or even cares what register goes to what. It is
defined by the calling conventions of function calls. I'm certain that the
subject of "pegging" a register to a variable in a compiler came up before in a
previous discussion but the closest my Google searches revealed was this one:
http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-November/011536.html

This begs the questions: Are you trying to make a compiler only for AMD64?
What operating systems do you plan on supporting with your compiler? Do you
know that LLVM is deliberately maintained as a cross-platform framework for many
operating systems and processors? What exactly are you trying to do that
requires such system-specific knowledge other than support a specific operating
system?

Maybe somebody else who is on the team can give a more specific answer than what
I gave.

I hope this helps,

--Sam

Do you really need that, or would it be enough to be able to get the
value of the register at the start of a function and be able to set it
(or pass it along) when calling other functions? If so, the easiest
way really is to define a calling convention that uses it as e.g. the
first parameter register. Then you can just read the value from that
parameter, and have your compiler automatically pass it as that
parameter to other functions.

If it ever changes you'll also need to add it as e.g. the first return
register so functions can return the current value in it (note that
functions can return multiple values by returning structs). To keep
things simple, it's probably best to treat it as a local variable in
your frontend: alloca at the start of the function, store to it at the
start of the function and after every call that returns the current
value for it, then load it whenever you need it. Optimization passes
will easily clean this up.
This is probably a good idea even if it doesn't change, simply because
it tells the code generator that the parameter register isn't changed.
Or at least, that the value in the register after the call is still
the value it needs to use. Otherwise, it would likely store it to the
stack before the first call and load it before every subsequent call.

After optimization, the code generator would most likely prefer to
keep the value in the right register (since it starts there and later
needs to be there), but it might get moved elsewhere if there's a lot
of code between uses of the variable and the register is better used
for other things. This is usually a *good* thing, because it should be
better for performance.
As Sam said, the only place this might mess things up is when
interrupt functions (which aren't explicitly called, meaning LLVM
wouldn't know the register needs to contain the variable at that point
in the code) are involved. Well, and maybe debuggers I suppose, if the
register is hardcoded somewhere or you explicitly ask for the register
instead of the variable.

P.S. If it's important (or just convenient) for you to use a
unmodified LLVM, you might be able to get these changes into the
repository if you post a patch to the commits list. GHC had their own
special calling convention committed, for example.

First of all, i would like to thank you both for your quick answers!

I am working on creating a backend for a language that already has a
compiler. This compiler already maps some virtual registers of the VM,
such as stack and heap pointers, to physical ones for performance and
interoperability. If I understood well, there is no simple, predefined
way to retain these conventions (custom pre-coloured registers) with
LLVM compiler infrastructure. I would be surprised if I was the first
one to have ever stumbled upon this problem!

~y.

No, like I said you're not the first one: GHC also had this problem
(but on perhaps a slightly larger scale: they seemed to have multiple
pinned registers). They fixed it by implementing a custom calling
convention, and getting it committed in the LLVM repository.

Hi Yiannis,

As has been said GHC had this problem (I'm the author of GHC's LLVM
backend). GHC uses 4 pinned registers on x86-32 and 16 on x86-64. The
solution is to use a custom calling convention. I would argue that
this is a better solution then having the registers completely
reserved as in the middle of a function llvm can spill those registers
to free them up for temporary use. Also, if when generating code you
know that one of the pinned registers doesn't actually store anything
useful for this function then you can avoid passing it on to the next
function so that the register will be free to use during the function.

Here is a link to the original discussion about this problem and the solution:

http://nondot.org/sabre/LLVMNotes/GlobalRegisterVariables.txt

You should also check out the GHC calling convention as there is a
good chance you could use it to get what you want and not have to
modify llvm at all. The calling conventions for X86 are defined in
'lib/Target/X86/X86CallingConv.td' in a very easy to read format.

On X86-64 the arguments are passed in R13, RBP, R12, RBX, R14, RSI,
RDI, R8, R9, R15, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, in that order.

So lets say the compiler you are trying to work with currently stores
a Sp and a Hp in %R13 and %R12 respectively. You could define your
functions like so:

function cc 10 void f (Sp, tmp1, Hp) {
  [...]
  tail call g (Sp', undef, Hp');
  ret void;
}

Cheers,
David

Hi,
  
I 'll work further on what you and Frits van Bommel suggested. Using a
custom calling convention seems like a reasonable approach after some
minor research on how that could be done with LLVM. By the way, great
work on your thesis, David! :slight_smile:

Thank you for your suggestions,
~y.

Hey people,

It has been some time since the last email on this topic. Since then i have successfully used your advice and implemented a custom calling convention for my backend that adheres to the runtime system’s ABI. To summarize what i do: i have three virtual registers (HP, P, NSP) pinned to some physical registers by defining it in the custom calling convention. I have also defined a custom return cc in order to guarantee that the physical registers also have the correct values on exit of the function. In that way i am sure that the registers are updated both on entrance and exit and that is exactly what i want.

The problem with that is the case of an ‘invoke’ call. According to the semantics of the invoke instruction the return value is not available when a stack unwind happens. From the Language Reference Manual:
“For the purposes of the SSA form, the definition of the value returned by the ‘invoke’ instruction is deemed to occur on the edge from the current block to the “normal” label. If the callee unwinds then no return value is available.”

In that case, how can i get the values of the pinned registers, i.e. HP, P and NSP, needed in the Fail code block?

Cheers,
Yiannis

You could store them in the exception, assuming your compiler is the
one generating the code that throws it...

Hi Frits and thanks for your quick response,

Can you elaborate more on this idea? How could i do that?
Let me explain quickly how i handle the 'register pinning' and what is
the problem in case it was not clear in the beginning (in llvm pseudocode):

{i64, i64, i64, i64} @main(i64 %in_hp, i64 %in_p, i64 %in_sp) {
  ;; In the entry block:
  %hp = alloca i64
  store %in_hp -> %hp
  %p = alloca i64
  store %in_p -> %p
  %sp = alloca i64
  store %in_sp -> %sp
  ......
  ;; before normal call
  %hp1 = load %hp
  %p1 = load %p
  %sp1 = load %sp
  {%hp2, %p2, %nsp2, %val} = call @foo(%hp1, %p1, %sp1, arg1, arg2)
  ;; in normal continuation
  store %hp2 -> %hp
  store %p2 -> %p
  store %sp2 -> %sp
  .......
  .......
  ;; before invoke call
  %hp3 = load %hp
  %p3 = load %p
  %sp3 = load %sp
  {%hp4, %p4, %nsp4, %val} = invoke @bar(%hp3, %p3, %sp3, ...) to label
%Continue unwind label %Cleanup
  ;; %Continue label (normal return)
  store %hp4 -> %hp
  store %p4 -> %p
  store %sp5 -> %sp
  .....
%Cleanup:
  ;; In this block i *cannot* access %hp4, %p4, %sp4
  .....
  ;; Return of main
  %hp5 = load %hp
  %p5 = load %p
  %sp5 = load %sp
  ret {%hp5, %p5, %sp5, 0}
}

The problem is that in the %Cleanup block i cannot perform the usual
store as the virtual registers %hp4, %p4, %sp4, are not available (due
to the semantics of the 'invoke' statement).

Sincerely,
Yiannis

The problem with that is the case of an 'invoke' call. According to the
semantics of the invoke instruction the return value is not available when
a stack unwind happens. From the Language Reference Manual:
"For the purposes of the SSA form, the definition of the value returned by
the 'invoke' instruction is deemed to occur on the edge from the current
block to the "normal" label. If the callee unwinds then no return value is
available."

In that case, how can i get the values of the pinned registers, i.e. HP, P
and NSP, needed in the Fail code block?

You could store them in the exception, assuming your compiler is the
one generating the code that throws it...

Hi Frits and thanks for your quick response,

Can you elaborate more on this idea? How could i do that?
Let me explain quickly how i handle the 'register pinning' and what is
the problem in case it was not clear in the beginning (in llvm pseudocode):

{i64, i64, i64, i64} @main(i64 %in_hp, i64 %in_p, i64 %in_sp) {
;; In the entry block:
%hp = alloca i64
store %in_hp -> %hp
%p = alloca i64
store %in_p -> %p
%sp = alloca i64
store %in_sp -> %sp
......
;; before normal call
%hp1 = load %hp
%p1 = load %p
%sp1 = load %sp
{%hp2, %p2, %nsp2, %val} = call @foo(%hp1, %p1, %sp1, arg1, arg2)
;; in normal continuation
store %hp2 -> %hp
store %p2 -> %p
store %sp2 -> %sp
.......
.......
;; before invoke call
%hp3 = load %hp
%p3 = load %p
%sp3 = load %sp
{%hp4, %p4, %nsp4, %val} = invoke @bar(%hp3, %p3, %sp3, ...) to label
%Continue unwind label %Cleanup
;; %Continue label (normal return)
store %hp4 -> %hp
store %p4 -> %p
store %sp5 -> %sp
.....
%Cleanup:
;; In this block i *cannot* access %hp4, %p4, %sp4

Reaching this block means that some kind of exception has been thrown, right?
If the code throwing the exception is generated by your compiler, you
can have it implicitly add some extra fields to it and store the
current hp/p/sp values there.
Here you can then just load those fields and store them to %hp/%p/%sp.

If the exception could have been thrown by code compiled by some other
compiler you need to be compatible with (or even one for an entirely
different language which doesn't know about those values) my
suggestion won't work.

.....
;; Return of main
%hp5 = load %hp
%p5 = load %p
%sp5 = load %sp
ret {%hp5, %p5, %sp5, 0}
}

The problem is that in the %Cleanup block i cannot perform the usual
store as the virtual registers %hp4, %p4, %sp4, are not available (due
to the semantics of the 'invoke' statement).

I understand, which was why I suggested storing them in the exception object.