Example scripts — gcc-python-plugin 0.16 documentation (original) (raw)

gcc-python-plugin

There are various sample scripts located in the examples subdirectory.

Once you’ve built the plugin (with make), you can run them via:

$ ./gcc-with-python examples/NAME-OF-SCRIPT.py test.c

show-docs.py

A trivial script to make it easy to read the builtin documentation for the gcc API:

$ ./gcc-with-python examples/show-docs.py test.c

with this source:

giving output:

Help on built-in module gcc:

NAME gcc

FILE (built-in)

CLASSES builtin.object BasicBlock Cfg Edge Function Gimple (truncated)

show-passes.py

You can see the passes being executed via:

$ ./gcc-with-python examples/show-passes.py test.c

This is a simple script that registers a trivial callback:

Sample python script, to be run by our gcc plugin

Show all the passes that get executed

import gcc

def my_pass_execution_callback(*args, **kwargs): (optpass, fun) = args print(args)

gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION, my_pass_execution_callback)

Sample output, showing passes being called on two different functions (mainand helper_function):

(gcc.GimplePass(name='*warn_unused_result'), gcc.Function('main')) (gcc.GimplePass(name='omplower'), gcc.Function('main')) (gcc.GimplePass(name='lower'), gcc.Function('main')) (gcc.GimplePass(name='eh'), gcc.Function('main')) (gcc.GimplePass(name='cfg'), gcc.Function('main')) (gcc.GimplePass(name='*warn_function_return'), gcc.Function('main')) (gcc.GimplePass(name='*build_cgraph_edges'), gcc.Function('main')) (gcc.GimplePass(name='*warn_unused_result'), gcc.Function('helper_function')) (gcc.GimplePass(name='omplower'), gcc.Function('helper_function')) (gcc.GimplePass(name='lower'), gcc.Function('helper_function')) (gcc.GimplePass(name='eh'), gcc.Function('helper_function')) (gcc.GimplePass(name='cfg'), gcc.Function('helper_function')) [...truncated...]

show-gimple.py

A simple script for viewing each function in the source file after it’s been converted to “GIMPLE” form, using GraphViz to visualize the control flow graph:

$ ./gcc-with-python examples/show-gimple.py test.c

It will generate a file test.png for each function, and opens it in an image viewer.

image of a control flow graph in GIMPLE form

The Python code for this is:

Show the GIMPLE form of each function, using GraphViz

import gcc from gccutils import get_src_for_loc, cfg_to_dot, invoke_dot

We'll implement this as a custom pass, to be called directly after the

builtin "cfg" pass, which generates the CFG:

class ShowGimple(gcc.GimplePass): def execute(self, fun): # (the CFG should be set up by this point, and the GIMPLE is not yet # in SSA form) if fun and fun.cfg: dot = cfg_to_dot(fun.cfg, fun.decl.name) # print dot invoke_dot(dot, name=fun.decl.name)

ps = ShowGimple(name='show-gimple') ps.register_after('cfg')

show-ssa.py

This is similar to show-gimple.py, but shows each function after the GIMPLE has been converted to Static Single Assignment form (“SSA”):

$ ./gcc-with-python examples/show-ssa.py test.c

As before, it generates an image file for each function and opens it in a viewer.

image of a control flow graph in GIMPLE SSA form

The Python code for this is:

Sample python script, to be run by our gcc plugin

Show the SSA form of each function, using GraphViz

import gcc from gccutils import get_src_for_loc, cfg_to_dot, invoke_dot

A custom GCC pass, to be called directly after the builtin "ssa" pass, which

generates the Static Single Assignment form of the GIMPLE within the CFG:

class ShowSsa(gcc.GimplePass): def execute(self, fun): # (the SSA form of each function should have just been set up) if fun and fun.cfg: dot = cfg_to_dot(fun.cfg, fun.decl.name) # print(dot) invoke_dot(dot, name=fun.decl.name)

ps = ShowSsa(name='show-ssa') ps.register_after('ssa')

show-callgraph.py

This simple script sends GCC’s interprocedural analysis data through GraphViz.

$ ./gcc-with-python examples/show-callgraph.py test.c

It generates an image file showing which functions call which other functions, and opens it in a viewer.

image of a call graph

The Python code for this is:

Sample python script, to be run by our gcc plugin

Show the call graph (interprocedural analysis), using GraphViz

import gcc from gccutils import callgraph_to_dot, invoke_dot

In theory we could have done this with a custom gcc.Pass registered

directly after "*build_cgraph_edges". However, we can only register

relative to passes of the same kind, and that pass is a

gcc.GimplePass, which is called per-function, and we want a one-time

pass instead.

So we instead register a callback on the one-time pass that follows it

def on_pass_execution(p, fn): if p.name == '*free_lang_data': # The '*free_lang_data' pass is called once, rather than per-function, # and occurs immediately after "*build_cgraph_edges", which is the # pass that initially builds the callgraph # # So at this point we're likely to get a good view of the callgraph # before further optimization passes manipulate it dot = callgraph_to_dot() invoke_dot(dot)

gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION, on_pass_execution)