JIT - GCC Wiki (original) (raw)
Just-In-Time Compilation (libgccjit.so)
GCC can be built as a shared library "libgccjit.so", for generating machine code from API calls, using GCC as the backend.
This shared library can then be dynamically-linked into bytecode interpreters and other such programs that want to generate machine code "on the fly" at run-time.
It can also be used for ahead-of-time code generation, for building standalone compilers (so the "jit" part of the name is now something of a misnomer).
The library provides a C API, along with a C++ wrapper API, with bindings for languages available from 3rd parties (see below).
The API is very high-level, and is designed in terms of C semantics (since you're probably going to want to interface with C code).
Status
libgccjit.so has been available in gcc since GCC 5, and we believe it has been API and ABI-compatible since then. See the API and ABI compatibility notes in the documentation.
The C API is mature at this point, though I'm open to adding new entrypoints to support functionality that I may have missed.
Although the C++ API ships within GCC, it should be regarded as more experimental that the C API.
The maintainer is David Malcolm <dmalcolm@redhat.com>
There are language bindings available from third parties for C#, D, OCaml, Perl, Python (2/3), and Rust.
Mailing list
There is a shared mailing list for both users and developers of the library: jit@gcc.gnu.org
You can subscribe by emailing jit-subscribe@gcc.gnu.org
The archives can be seen at: http://gcc.gnu.org/ml/jit/
Documentation
Documentation for the API can be seen at: https://gcc.gnu.org/onlinedocs/jit/
Installation via packages
Fedora and RHEL
Running:
1 sudo dnf install libgccjit-devel
should give you both the JIT library (libgccjit) and the header files needed to develop against it (libgccjit-devel):
Other distributions
TODO: what are the packages called in other distributions?
Building it from source
See the notes on working on the JIT library in the documentation.
Language Bindings
- Python: https://github.com/davidmalcolm/pygccjit with documentation at:
- D: https://github.com/ibuclaw/gccjitd
- OCaml: https://github.com/nojb/ocaml-gccjit
- C#: https://github.com/mjsabby/GCCSharp
- Perl: https://github.com/vickenty/gccjit-perl
- Rust: https://github.com/swgillespie/gccjit.rs
Who's using this code?
- https://github.com/rust-lang/rustc_codegen_gcc is a work-in-progress experiment at using the ahead-of-time compilation parts of libgccjit to add a GCC-based code-generation backend to rustc
- I've been able to successfully use this API to add JIT-compilation to a toy bytecode interpreter:
- https://github.com/davidmalcolm/jittest
- (where regvm.cc uses this API to compile a bytecode function into machine code).
- Ravi, a derivative of Lua, with a JIT compiler: https://github.com/dibyendumajumdar/ravi
- Experimental work-in-progress port of GNU Octave's JIT compiler to libgccjit:
- "coconut", an experimental JIT for CPython 3.*:
- Experimental work-in-progress backend for PyPy's JIT:
- Ahead-of-time compilation of Emacs bytecode:
Architecture
The idea is that GCC is configured with a special --enable-host-shared option, which leads to it being built as position-independent code. You would configure it with host==target, given that the generated machine code will be executed within the same process (the whole point of JIT).
libgccjit.so is built against libbackend.a. To the rest of GCC, it looks like a "frontend" (in the "gcc/jit" subdir), but the parsing hook works by replaying a record of the API calls made by client code.
You can see a diagram of how it all fits together at: http://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/jit/notes.txt
The jit "frontend" requires --enable-host-shared, so it is off by default, so you need to configure with:
- --enable-host-shared --enable-languages=jit
to get the jit (and see caveats above).
The library API hides GCC's internals, and tries to be much more typesafe than GCC's, giving something rather like Andrew MacLeod's proposed changes - client code does not see "tree", instead dealing with types, rvalues, lvalues, basic blocks, etc. It is pure C, given the horror stories I have heard about people dealing with C++ ABIs.
The API deliberately uses C terminology, given that it's likely that the user will want to be plugging the JIT-generated code into a C/C++ program (or library).
News
- GCC 10 changes
- GCC 9 changes
- GCC 8 changes
- GCC 7 changes
- GCC 6 changes
- 2014-11-11: Merge of jit branch into trunk for GCC 5: https://gcc.gnu.org/ml/gcc/2014-11/msg00163.html
- 2014-07-19: Talk on libgccjit at GNU Tools Cauldron 2014: http://dmalcolm.fedorapeople.org/presentations/cauldron-2014/jit/
- 2014-02-27: Changeover of API from being based on label-placement to using basic blocks: http://gcc.gnu.org/git/?p=gcc.git;a=commit;h=a0b0a25243dd4c3e2967ec76449f901cc6c647de
- 2013-10-09: Discussion on main GCC list: http://gcc.gnu.org/ml/gcc/2013-10/msg00091.html
- 2013-10-02: Initial announcement: http://gcc.gnu.org/ml/gcc-patches/2013-10/msg00228.html