LLVM JIT Questions

Hi all,

For my current project I need a couple of informations about JIT. I seen similar questions already, but the answers are a bit older and I hope somebody can provide me a recent information.

1. In my project I frequently construct LLVM IR, compile it and execute with JIT. Because the constructed IR is often the same (but can vary depending on input data) I would like to cache produced machine code on the disk. There is no JIT API for dumping and loading of compiled code.

Are there any plans to add this feature in the near future ?

How complex would it be to implement this for somebody who has only experience with LLVM code generation, but no deep knowledge of JIT internals ?

2. I also need to interface with C-libraries which are either loaded as a shared library or pre-compiled with clang and loaded as BC file. However, LLVM does not provide a way how to construct function signature compatible with the C-ABI of the specific platform. I know that clang library has internally this information, but I need this functionality without clang.

Is there any documentation which describes how to do generate C-ABI compatible LLVM functions or code that implements this functionality ?

Thanks,

Dmitri

Hi Dmitri,

Regarding your first question, if you can use the MCJIT engine a caching mechanism will be available very soon. I'm preparing to commit a patch today to add this capability. I'm not sure what it would take to get something similar working with the older JIT engine. I expect it would take a fair amount of work because the older JIT engine isn't designed around object loading as the MCJIT engine is.

Regarding your second question, there might be more than one way to do this, but once you have an llvm::Function (but before you JIT the code) you should be able to use llvm::Function::setCallingConv().

-Andy

Hi Dmitri,

Regarding your first question, if you can use the MCJIT engine a caching
mechanism will be available very soon. I'm preparing to commit a patch
today to add this capability. I'm not sure what it would take to get
something similar working with the older JIT engine. I expect it would
take a fair amount of work because the older JIT engine isn't designed
around object loading as the MCJIT engine is.

I would expect it to be very hard to do with the old JIT, because it JITs
the machine code in a "loaded" form (absolute addresses put into the needed
places). This is tightly coupled with the current execution and does not
apply to other executions. MCJIT allows this by virtue of having a
not-yet-loaded ELF object which can be cached for later use. I imagine this
is what you do in your patch, Andy.

Eli

Yes, exactly. My patch adds a new ObjectCache class which can be registered with MCJIT. MCJIT will then call this component before attempting to generate code to see if it has a cached object image for a given module. If the ObjectCache has a cached object, MCJIT will skip the code generation step and just perform linking and loading. If the ObjectCache does not have a cached version MCJIT will generate code as usual and then pass the generated object image to the ObjectCache to be cached before MCJIT performs its linking and loading.

The ObjectCache is going to be offered as an abstract base class only. Clients will need to implement their own mechanism for identifying modules and storing cached images, though I do have a unit test which provides a very simple reference implementation.

This mechanism is not coupled directly with the ELF format. It will work with MachO objects as well, to the extent that MachO is supported by MCJIT.

-Andy

Yes, exactly. My patch adds a new ObjectCache class which can be
registered with MCJIT. MCJIT will then call this component before
attempting to generate code to see if it has a cached object image for a
given module. If the ObjectCache has a cached object, MCJIT will skip the
code generation step and just perform linking and loading. If the
ObjectCache does not have a cached version MCJIT will generate code as
usual and then pass the generated object image to the ObjectCache to be
cached before MCJIT performs its linking and loading.****

** **

The ObjectCache is going to be offered as an abstract base class only.
Clients will need to implement their own mechanism for identifying modules
and storing cached images, though I do have a unit test which provides a
very simple reference implementation.****

** **

This mechanism is not coupled directly with the ELF format. It will work
with MachO objects as well, to the extent that MachO is supported by MCJIT.

That sounds like a good approach.

Eli

This sounds great, but will it work on Windows as well ?

I considered MCJIT for my work, but was not sure if there are any features supported by old JIT but missing in MCJIT.

Thanks,

Dmitri

Yes, MCJIT works on Windows (though it generates ELF object images).

The primary differences between MCJIT and JIT have to do with the way that they work. MCJIT does not support lazy compilation of functions as JIT does because MCJIT works at the Module level rather than the Function level. You can work around this limitation to some extent by creating multiple smaller Modules. However, at the moment you need one instance of MCJIT per Module. We plan to address that, but right now it is a limitation.

The object caching support is in place as of r180150.

-Andy

Hi Andrew,

Hi Dmitri,

Regarding your first question, if you can use the MCJIT engine a caching mechanism will be available very soon. I’m preparing to commit a patch today to add this capability. I’m not sure what it would take to get something similar working with the older JIT engine. I expect it would take a fair amount of work because the older JIT engine isn’t designed around object loading as the MCJIT engine is.

Regarding your second question, there might be more than one way to do this, but once you have an llvm::Function (but before you JIT the code) you should be able to use llvm::Function::setCallingConv().

SetCallingConv is not enough. For example consider following C code:

typedef struct S { int a, b, c; } S;

void doS(S s) { … }

Is compled on Linux x86 32bit as

%struct.S = type { i32, i32, i32 }

define void @doS(i32 %s.0, i32 %s.1, i32 %s.2) nounwind { … }

And on Linux x86 64bit as

%0 = type { i64, i32 }
%struct.S = type { i32, i32, i32 }

define void @doS(i64 %s.coerce0, i32 %s.coerce1) nounwind { … }

Dmitri