Skip to content
playX edited this page May 21, 2019 · 2 revisions

GCCJIT library helps to create a frontend for GCC. This library generates GIMPLE tree which is very close to C and then translates it into RTL where GCC performs all optimizations with code generation.

GCCJIT allows not only JIT compiling your program but also AOT compiling and then emitting executable binary file.

A typical frontend for GCC with GCCJIT:

  • Translates AST into GIMPLE directly (that's what Jazz do)
  • Translates AST into some HIR (High-level intermediate representation) or to MIR( Middle-level intermediate representation)
  • Performs optimizations on HIR or MIR
  • Translates HIR or MIR into GIMPLE
  • GCCJIT translates GIMPLE into RTL (Register transfer language)
  • GCC optimizes RTL code
  • Outputs executable binary file or JIT executes code.

Advantages

A lot of supported targets

GCC developed from 1987 and got a lot of backends for different CPUs(More than LLVM supports!). You can check all supported architectures there: https://gcc.gnu.org/backends.html

Optimizations

GCC performs a lot of optimizations on RTL and makes your code very fast.

Easy to use

When with LLVM you compiling to IR with GCCJIT you compile to "high-level" language that was very close to C.

Easy to generate executable binaries and link with libraries

GCCJIT provides the functionality to emit object/assembly/binary files without any problems. This code I use in Jazz compiler to emit executable binary:

            self.ctx.add_driver_option("-lc"); // link libc
            self.ctx.add_driver_option("-lm"); // link libm
            let out_path = if !self.context.output.is_empty()
            {
                self.context.output.clone()
            }
            else
            {
                "a.out".to_owned()
            };
            let kind = if self.context.emit_obj
            {
                OutputKind::ObjectFile
            }
            else if self.context.shared
            {
                OutputKind::DynamicLibrary
            }
            else
            {
                OutputKind::Executable
            };
            self.ctx.compile_to_file(kind, out_path);

Disadvantages

Documentation

GCCJIT don't have good documentation so you need "experiment" with the library to make your compiler work.

The absence of some casts

With GCCJIT you can't cast an int to ptr and vice versa and you can't cast vector types properly.

Unfinished binary operators

You can't just add gcc_jit_context_new_binary_op on ssa_vectori32 + 42,you must need create vector from 42 number too.

Errors from nothing

For example:

JazzModule: Snake/snake.jazz:195:18: error: gcc_jit_block_add_assignment: mismatching types: assignment to game->display (type: struct ALLEGRO_DISPLAY *) from display (type: struct ALLEGRO_DISPLAY *)