GCC/Frontend
From Gentoo Wiki
< GCC
Jump to:navigation
Jump to:search
This article describes how to write a frontend for GCC using JIT.
GCC uses 3 main intermediate representation: GENERIC, GIMPLE, and RTL. Traditionally, one could write a frontend using GENERIC. However, this is not a trivial task due to lack of documentation and no C API for GENERIC, only C++. With JIT, it is much easier to write a GCC frontend.
Prerequisites
GCC must have JIT flag:
sys-devel/gcc jit
JIT provides both C API and C++ API. Only the C API will be used for this page.
Tutorial
Note
Depending on the GCC version, some JIT functions like gcc_jit_function_new_temp() will not exist. Their presence can be tested using #ifdef LIBGCCJIT_HAVE_*. The instructions are from https://gcc.gnu.org/onlinedocs/jit/intro/
Depending on the GCC version, some JIT functions like gcc_jit_function_new_temp() will not exist. Their presence can be tested using #ifdef LIBGCCJIT_HAVE_*. The instructions are from https://gcc.gnu.org/onlinedocs/jit/intro/
Create a C file:
#include <libgccjit.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv){
if(argc < 2){
fprintf(stderr, "Expected file argument\n");
exit(1);
}
// GCC uses the context to store functions, global variables, types and more
gcc_jit_context *ctxt = gcc_jit_context_acquire ();
// gcc_jit_type represents a type within the library. These are required for main() and it's return value.
gcc_jit_type *type_int = gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *type_char_ptr = gcc_jit_type_get_pointer(gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_CHAR));
gcc_jit_type *type_char_ptr_ptr = gcc_jit_type_get_pointer(type_char_ptr);
// gcc_jit_param are function parameters and is use to contruct a function.
gcc_jit_param *params[2];
params[0] = gcc_jit_context_new_param(ctxt, NULL, type_int, "argc");
params[1] = gcc_jit_context_new_param(ctxt, NULL, type_char_ptr_ptr, "argv");
// GCC_JIT_FUNCTION_EXPORTED makes the function visible, required for main().
gcc_jit_function *func_main = gcc_jit_context_new_function(ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, type_int, "main", 2, params, 0);
// gcc_jit_block is a sequence of statements. The first block is where the function starts. All blocks must be terminated.
// Blocks can link to other blocks, acting like a linked list.
gcc_jit_block *block_main = gcc_jit_function_new_block(func_main, NULL);
// Only required statement in main(). Equal to return 0;
gcc_jit_block_end_with_return(block_main, NULL, gcc_jit_context_new_rvalue_from_int(ctxt, type_int, 0));
// Equal to -O2
gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 2);
// Compile the context to a file
gcc_jit_context_compile_to_file(ctxt, GCC_JIT_OUTPUT_KIND_EXECUTABLE, argv[1]);
}
Compile the file:
user $
gcc usingjit.c -lgccjit -O2 -o usingjit.exe
Run the executable to create executable from JIT:
user $
./usingjit.exe jitoutput.exe
If everything went well, the executable returns 0:
user $
./jitoutput.exe
user $
echo $?
0