Common mechanisms to extend compilers fall into two categories.
Frontend macros, staging or partial evaluation systems can be used
to programmatically remove abstraction and specialize programs
before they enter the compiler. Alternatively, some compilers allow
extending the internal workings by adding new transformation passes
at different points in the compile chain or adding new intermediate
representation (IR) types. None of these mechanisms alone is
sufficient to handle the challenges posed by high level data
structures. This paper shows a novel way to combine them to yield
benefits that are greater than the sum of the parts.
Instead of using staging merely as a front end, we implement
internal compiler passes using staging as well. These internal
passes delegate back to program execution to construct the
transformed IR. Staging is known to simplify program generation, and
in the same way it can simplify program transformation. Defining a
transformation as a staged IR interpreter is simpler than
implementing a low-level IR to IR transformer. With custom IR nodes,
many optimizations that are expressed as rewritings from IR nodes to
staged program fragments can be combined into a single pass,
mitigating phase ordering problems. Speculative rewriting can
preserve optimistic assumptions around loops.
We demonstrate several powerful program optimizations using this
architecture that are particularly geared towards data structures: a
novel loop fusion and deforestation algorithm, array of struct to
struct of array conversion, object flattening and code generation for
heterogeneous parallel devices. We validate our approach using
several non trivial case studies [NdR: linear algebra, Regular
Expression Matchers, Collection and Query Operations, String
Templates] that exhibit order of magnitude speedups in
experiments.
http://ppl.stanford.edu/papers/popl13_rompf.pdf