Hi,
I wonder if a GCC plugin (GCC 5.3 or newer) can create its own builtins
or "emulate" builtins with the help of the inliner (after IPA passes).
Any suggestions are appreciated.
Now, here is the long story.
My GCC plugin should instrument the calls to some functions, namely add
some code before and may be after the call. The code to be compiled is
written in C, if that matters.
For example,
obj = calloc(num, sz);
should become something like this after the instrumentation:
__size = num * sz;
__do_something(__size);
obj = calloc(num, sz);
__do_something() is a function defined elsewhere, __size is a local
variable added by the plugin. The plugin adds a GIMPLE pass to do the
instrumentation.
In this simple case, I can, of course, add the necessary GIMPLE
statements explicitly to implement "__size = num * sz", and that would
be fine. However, when it is not only "calloc()" but rather dozens of
functions that should be instrumented, and each of these needs different
statements before it, things get tedious and error-prone.
It would help if I could somehow write the helpers in C, for example:
static size_t helper_calloc(size_t nmemb, size_t size)
{
return nmemb * size;
}
It could be defined, say, in a header file specified in "-include"
compiler option.
Then I could instrument that call to calloc() as follows (everything is
actually done at GIMPLE level but the examples are in C for clarity):
__size = helper_calloc(num, sz);
__do_something(__size);
obj = calloc(num, sz);
After that, I'd like to let GCC know somehow that helper_calloc() should
be inlined there. This is where I am stuck now.
Creating a custom builtin function could probably help but it seems, a
GCC plugin cannot create new builtins. At least, with
add_builtin_function() from gcc/langhooks.c. add_builtin_function()
needs a unique numeric ID of the function, "function_code", from enum
built_in_function. A GCC plugin cannot add new values to this enum.
I went a different way and invoked the inliner explicitly in my GIMPLE
pass to inline the call to helper_calloc() and such:
...
unsigned int todo = early_inliner(cfun);
...
This did not work first because my GIMPLE pass needs to be executed way
after the IPA passes. And during the IPA, the compiler finds
helper_calloc(), which is unused at that moment, and removes it. So the
inliner considers "helper_calloc(num, sz)" as a call to an external
function and cannot inline it, of course.
I added "__attribute__((__used__))" for helper_calloc() and now the
function was available to my GIMPLE pass, the inlining went fine. But!
As the function was marked as "__used__", the compiler placed it in the
object file. This is logical but less than ideal in my case because this
function itself will no longer be used and will only bloat the object file.
Perhaps, there is a better way to add such function calls in a plugin,
either as the calls to builtins or inlines?
Any suggestions?
Regards,
Evgenii