GNU C Compiler Internals/Creating a Compiler Extension 3 4
In this section we describe the creation of a new compiler extension step-by-step. First, one needs to download the GCC and patch it with the GEM patch. After that one can start writing the compiler extension. When the extension is ready one can compile other programs using the GEM-patched version of GCC and the new compiler extension.
Installation
editDownload GEM framework from here. Unpack it and type make all. This will download a copy of GCC, patch it with GCC patch, compile and install GCC, and build examples.
The C function overloading example allows one to overload functions in C just like in C++:
/* one function */ void test(int a, int b) { printf("%d %d\n", a, b); } /* overloaded function */ void test(char *a, int b) { printf("%s %d\n", a, b); } void main() { test(1,2); test("abc", 1); }
Let us consider the CFO example in more detail.
C function overloading
editThe source code of the extension is located in ./examples/cfo/cfo.c file. The following hooks are implemented:
gem_start_decl() gem_start_function() gem_build_function_call()
The idea of the implementation is to modify the name of each function declared more than once. The names of these functions are modifier to include the type information of the arguments. For example, function test(int, int) is renamed into test_i_i(int, int). The renaming takes place in function cfo_alias_decl().
Functions cfo_start_decl() and gem_start_function() call this function. It looks up the name of the function being declared and returns immediately if the name is not found:
cfo_find_symtab(&t_func, func_name); if (t_func==NULL_TREE || DECL_BUILT_IN(t_func)) { return; }
Therefore, the names of non-overloaded functions are not changed. This maintains the compatibility with the unmodified compiler.
If the function with this name was declared previously then the extension checks if an alias with the arguments type information was created:
strcpy(new_name, func_name); strcat(new_name, cfo_build_name(TREE_PURPOSE(T_O(declarator, 1)))); cfo_find_symtab(&t_func_alias, name);
Function cfo_build_name() builds the name of the function arguments. An alias is created if it was not created before.
t_alias_attr=tree_cons(get_identifier("alias"), tree_cons(NULL_TREE, get_identifier(name), NULL_TREE), NULL_TREE); TYPE_ATTRIBUTES(T_T(t_func)) = t_alias_attr; DECL_ATTRIBUTES(t_func)=t_alias_attr;
Finally, the new declaration is renamed so that it includes the type information of the arguments:
T_O(declarator,0) = get_identifier(new_name);
Function cfo_build_function_call() builds the name of the function that includes the argument type information and looks it up in the symbol table. If the name is found then the function name is replace in the function call. If the name is not found then the function was not overloaded and the name of the function being called is not changed. Build the new name:
name = cfo_build_decl_name(t_func, t_parm);
Check if this identifier was parsed previously:
t_new_func = get_identifier(name);
If it was then get the declaration:
if (t_new_func) { t_new_func = lookup_name(t_new_func); }
If the declaration is found then replace the function:
*func = t_new_func;