How to add a builtin function in a GCC plugin?

It is possible for a GCC plugin to add a new builtin function? If so, how to do it properly?

GCC version is 5.3 (or newer). The code is compiled and processed by the plugin written in C.

It is mentioned in the rationale for GCC plugins at gcc-melt.org that this is doable but I cannot see how.

As far as I can see in the sources of GCC, the builtins are created using add_builtin_function() from gcc/langhooks.c:

tree
add_builtin_function (const char *name,
      tree type,
      int function_code,
      enum built_in_class cl,
      const char *library_name,
      tree attrs)

It is more or less clear which values the arguments of this function should have, except for function_code, a unique numeric ID of the function.

Looks like (see add_builtin_function_common()), a value from enum built_in_function is expected there but a GCC plugin cannot change that enum.

One cannot pass any random value greater than END_BUILTINS as function_code either, it seems. builtin_decl_implicit() and builtin_decl_explicit() would have a failed assertion in that case.

So, what is the proper way to add a builtin in a GCC plugin (without using MELT and such, just GCC plugin API)?

Update I looked again at the implementation of add_builtin_function_common() and of langhooks.builtin_function() for C as well as at how these are used in GCC. It seems that 0 is acceptable as function_code in some cases. You cannot use builtin_decl_implicit() then but you can save the DECL returned by add_builtin_function() and use it later.

Looks like the only event when I can try to create built-ins that way is PLUGIN_START_UNIT (otherwise GCC may crash due to external_scope variable being NULL).

I tried the following at that stage (fntype was created before):

decl = add_builtin_function (
    "my_helper", fntype,
    0 /* function_code */,
    BUILT_IN_NORMAL /* enum built_in_class cl */,
    NULL /* library_name */,
    NULL_TREE /* attrs */)

my_helper was defined in a different C source file compiled and linked with the main source file. Then I used decl to insert the calls to that function into other functions (gimple_build_call) during my GIMPLE pass.

GCC output no errors and indeed inserted the call to my_helper but as a call to an ordinary function. I actually needed a builtin to avoid a call but rather insert the body of the function.

On the other hand, tsan0 pass, which executes right after my pass, inserts the calls of builtin functions just like one would expect: there is no explicit call as a result, just the body of the function is inserted. Its builtins, however, are defined by GCC itself rather than by the plugins.

So I suppose my builtin still needs something to be a valid builtin, but I do not know what it is. What could that be?


Solution 1:

I'm assuming what you want to do (from your comment and linked post) is insert C code into a function. In that case, I would have thought you wouldn't need to go so far as to write a compiler plugin. Have a look at Boost.Preprocessor, which can do very advanced manipulations of C code using only the preprocessor.