Working with callbacks¶
One way to work with GCC from the Python plugin is via callbacks. It’s possible to register callback functions, which will be called when various events happen during compilation.
For example, it’s possible to piggyback off of an existing GCC pass by using
gcc.PLUGIN_PASS_EXECUTION
to piggyback off of an existing GCC pass.
-
gcc.
register_callback
(event_id, function, [extraargs, ]**kwargs)¶ Wire up a python function as a callback. It will be called when the given event occurs during compilation. For some events, the callback will be called just once; for other events, the callback is called once per function within the source code being compiled. In the latter case, the plugin passes a
gcc.Function
instance as a parameter to your callback, so that you can work on it:import gcc def my_pass_execution_callback(*args, **kwargs): print('my_pass_execution_callback was called: args=%r kwargs=%r' % (args, kwargs)) gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION, my_pass_execution_callback)
The exact arguments passed to your callback vary: consult the documentation for the particular event you are wiring up to (see below).
You can pass additional arguments when registering the callback - they will be passed to the callback after any normal arguments. This is denoted in the descriptions of events below by *extraargs.
You can also supply keyword arguments: they will be passed on as keyword arguments to the callback. This is denoted in the description of events below by **kwargs.
The various events are exposed as constants within the gcc module and directly wrap GCC’s plugin mechanism.
The following GCC events are currently usable from the Python plugin via
gcc.register_callback()
:
ID | Meaning |
---|---|
gcc.PLUGIN_ATTRIBUTES |
For creating custom GCC attributes |
gcc.PLUGIN_PRE_GENERICIZE |
For working with the AST in the C and C++ frontends |
gcc.PLUGIN_PASS_EXECUTION |
Called before each pass is executed |
gcc.PLUGIN_FINISH_UNIT |
At the end of working with a translation unit (aka source file) |
gcc.PLUGIN_FINISH_TYPE |
After a type has been parsed |
gcc.PLUGIN_FINISH_DECL |
After a declaration has been parsed (GCC 4.7 or later) |
gcc.PLUGIN_FINISH |
Called before GCC exits |
-
gcc.
PLUGIN_ATTRIBUTES
¶ Called when GCC is creating attributes for use with its non-standard __attribute__(()) syntax.
If you want to create custom GCC attributes, you should register a callback on this event and call
gcc.register_attribute()
from within that callback, so that they are created at the same time as the GCC’s built-in attributes.No arguments are passed to your callback other than those that you supply yourself when registering it:
(*extraargs, **kwargs)See creating custom GCC attributes for examples and more information.
-
gcc.
PLUGIN_PASS_EXECUTION
¶ Called when GCC is about to run one of its passes.
Arguments passed to the callback are:
(ps, fun, *extraargs, **kwargs)where ps is a
gcc.Pass
and fun is agcc.Function
. Your callback will typically be called many times: there are many passes, and each can be invoked zero or more times per function (in the code being compiled)More precisely, some passes have a “gate check”: the pass first checks a condition, and only executes if the condition is true.
Any callback registered with gcc.PLUGIN_PASS_EXECUTION will get called if this condition succeeds.
The actual work of the pass is done after the callbacks return.
In pseudocode:
if pass.has_gate_condition: if !pass.test_gate_condition(): return invoke_all_callbacks() actually_do_the_pass()
For passes working on individual functions, all of the above is done per-function.
To connect to a specific pass, you can simply add a conditional based on the name of the pass:
import gcc def my_callback(ps, fun): if ps.name != '*warn_function_return': # Not the pass we want return # Do something here print(fun.decl.name) gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION, my_callback)
-
gcc.
PLUGIN_PRE_GENERICIZE
¶ Arguments passed to the callback are:
(fndecl, *extraargs, **kwargs)where fndecl is a
gcc.Tree
representing a function declaration within the source code being compiled.
-
gcc.
PLUGIN_FINISH_UNIT
¶ Called when GCC has finished compiling a particular translation unit.
Arguments passed to the callback are:
(*extraargs, **kwargs)
-
gcc.
PLUGIN_FINISH_DECL
¶ Note
Only available in GCC 4.7 onwards.
Called when GCC has finished compiling a declaration (variables, functions, parameters to functions, types, etc)
Arguments passed to the callback are:
(decl, *extraargs, **kwargs)where decl is a
gcc.Declaration
.
-
gcc.
PLUGIN_FINISH_TYPE
¶ Called when GCC has finished parsing a type. Arguments to the callback are:
(type, *extraargs, **kwargs)where type is a
gcc.Type
.
-
gcc.
PLUGIN_FINISH
¶ Called before GCC exits.
Arguments passed to the callback are:
(*extraargs, **kwargs)
The remaining GCC events aren’t yet usable from the plugin; an attempt to register a callback on them will lead to an exception being raised. Email the gcc-python-plugin’s mailing list if you’re interested in working with these):
ID | Meaning |
---|---|
gcc.PLUGIN_PASS_MANAGER_SETUP |
To hook into pass manager |
gcc.PLUGIN_INFO |
Information about the plugin |
gcc.PLUGIN_GGC_START |
For interacting with GCC’s garbage collector |
gcc.PLUGIN_GGC_MARKING |
(ditto) |
gcc.PLUGIN_GGC_END |
(ditto) |
gcc.PLUGIN_REGISTER_GGC_ROOTS |
(ditto) |
gcc.PLUGIN_REGISTER_GGC_CACHES |
(ditto) |
gcc.PLUGIN_START_UNIT |
Called before processing a translation unit (aka source file) |
gcc.PLUGIN_PRAGMAS |
For registering pragmas |
gcc.PLUGIN_ALL_PASSES_START |
Called before the first pass of the “all other passes” gcc.Pass catchall |
gcc.PLUGIN_ALL_PASSES_END |
Called after last pass of the “all other passes” gcc.Pass catchall |
gcc.PLUGIN_ALL_IPA_PASSES_START |
Called before the first IPA pass |
gcc.PLUGIN_ALL_IPA_PASSES_END |
Called after last IPA pass |
gcc.PLUGIN_OVERRIDE_GATE |
Provides a way to disable a built-in pass |
gcc.PLUGIN_EARLY_GIMPLE_PASSES_START |
|
gcc.PLUGIN_EARLY_GIMPLE_PASSES_END |
|
gcc.PLUGIN_NEW_PASS |