Optimization passes

Working with existing passes

GCC organizes the optimization work it does as “passes”, and these form trees: passes can have both successors and child passes.

There are actually five “roots” to this tree:

classmethod gcc.Pass.get_roots()

Returns a tuple of gcc.Pass instances, giving the 5 top-level passes within GCC’s tree of passes, in the order described above.

classmethod gcc.Pass.get_by_name(name)

Get the gcc.Pass instance for the pass with the given name, raising ValueError if it isn’t found

class gcc.Pass

This wraps one of GCC’s struct opt_pass *, but the wrapper class is still a work-in-progress. Hopefully we’ll eventually be able to subclass this and allow creating custom passes written in Python.

Beware: “pass” is a reserved word in Python, so use e.g. ps as a variable name for an instance of gcc.Pass

name

The name of the pass, as a string

sub

The first child pass of this pass (if any)

next

The next sibling pass of this pass (if any)

properties_required
properties_provided
properties_destroyed

Currently these are int bitfields, expressing the flow of data betweeen the various passes.

They can be accessed using bitwise arithmetic:

if ps.properties_provided & gcc.PROP_cfg:
     print(fn.cfg)

Here are the bitfield flags:

Mask Meaning Which pass sets this up? Which pass clears this?
gcc.PROP_gimple_any Is the full GIMPLE grammar allowed? (the frontend) “expand”
gcc.PROP_gimple_lcf Has control flow been lowered? “lower” “expand”
gcc.PROP_gimple_leh Has exception-handling been lowered? “eh” “expand”
gcc.PROP_cfg Does the gcc.Function have a non-None “cfg”? “cfg” “*free_cfg”
gcc.PROP_referenced_vars Do we have data on which functions reference which variables? (Dataflow analysis, aka DFA) “*referenced_vars” (none)
gcc.PROP_ssa Is the GIMPLE in SSA form? “ssa” “expand”
gcc.PROP_no_crit_edges Have all critical edges within the CFG been split? “crited” (none)
gcc.PROP_rtl Is the function now in RTL form? (rather than GIMPLE-SSA) “expand” “*clean_state”
gcc.PROP_gimple_lomp Have OpenMP directives been lowered into explicit calls to the runtime library (libgomp) “omplower” “expand”
gcc.PROP_cfglayout Are we reorganizing the CFG into a more efficient order? “into_cfglayout” “outof_cfglayout”
gcc.PROP_gimple_lcx Have operations on complex numbers been lowered to scalar operations? “cplxlower” “cplxlower0”

There are four subclasses of gcc.Pass:

class gcc.GimplePass

Subclass of gcc.Pass, signifying a pass called per-function on the GIMPLE representation of that function.

class gcc.RtlPass

Subclass of gcc.Pass, signifying a pass called per-function on the RTL representation of that function.

class gcc.SimpleIpaPass

Subclass of gcc.Pass, signifying a pass called once (not per-function)

class gcc.IpaPass

Subclass of gcc.Pass, signifying a pass called once (not per-function)

Creating new optimization passes

You can create new optimization passes. This involves three steps:

  • subclassing the appropriate gcc.Pass subclass (e.g. gcc.GimplePass)
  • creating an instance of your subclass
  • registering the instance within the pass tree, relative to another pass

Here’s an example:

# Here's the (trivial) implementation of our new pass:
class MyPass(gcc.GimplePass):
   # This is optional.
   # If present, it should return a bool, specifying whether or not
   # to execute this pass (and any child passes)
   def gate(self, fun):
       print('gate() called for %r' % fun)
       return True

   def execute(self, fun):
       print('execute() called for %r' % fun)

# We now create an instance of the class:
my_pass = MyPass(name='my-pass')

# ...and wire it up, after the "cfg" pass:
my_pass.register_after('cfg')

For gcc.GimplePass and gcc.IpaPass, the signatures of gate and execute are:

gate(self, fun)
execute(self, fun)

where fun is a gcc.Function.

For gcc.SimpleIpaPass and gcc.IpaPass, the signature of gate and execute are:

gate(self)
execute(self)

If an unhandled exception is raised within gate or execute, it will lead to a GCC error:

/home/david/test.c:36:1: error: Unhandled Python exception raised calling 'execute' method
Traceback (most recent call last):
  File "script.py", line 79, in execute
   dot = gccutils.tree_to_dot(fun)
NameError: global name 'gccutils' is not defined
gcc.Pass.register_after(name[, instance_number=0])

Given the name of another pass, register this gcc.Pass to occur immediately after that other pass.

If the other pass occurs multiple times, the pass will be inserted at the specified instance number, or at every instance, if supplied 0.

Note

The other pass must be of the same kind as this pass. For example, if it is a subclass of gcc.GimplePass, then this pass must also be a subclass of gcc.GimplePass.

If they don’t match, GCC won’t be able to find the other pass, giving an error like this:

cc1: fatal error: pass 'ssa' not found but is referenced by new pass 'my-ipa-pass'

where we attempted to register a gcc.IpaPass subclass relative to ‘ssa’, which is a gcc.GimplePass

gcc.Pass.register_before(name[, instance_number=0])

As above, but this pass is registered immediately before the referenced pass.

gcc.Pass.replace(name[, instance_number=0])

As above, but replace the given pass. This method is included for completeness; the result is unlikely to work well.

Table Of Contents

Previous topic

Gimple statements

Next topic

Usage example: a static analysis tool for CPython extension code

This Page