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 a gcc.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