MimIR 0.1
MimIR is my Intermediate Representation
|
Passes in MimIR are the main infrastructure and preferred method when implementing code transformations. However, nothing stops you from manually iterating and transforming the program. This is usually only necessary if you need a very specific iteration behavior for your transformation.
Passes are managed by the PassManager. You can put together your optimization pipeline like so:
Note how some passes depend on other passes. For example, the CopyPropagation depends on the BetaReduction and EtaExpansion. In contrast to traditional passes in compilers, MimIR's PassMan will run all passes in tandem and combine the obtained results into the most optimal solution and, hence, avoid the dreaded phase-ordering problem.
There are two kind of passes in MimIR:
In order to write a rewrite pass, you have to inherit from RWPass. Usually, you are only interested in looking for code patterns that only occur in specific mutables - typically Lambdas. You can filter for these mutables by passing it as template parameter to RWPass when inherting from it. The main hook to the PassMan, is the rewrite method. As an example, let's have a look at the Alloc2Malloc pass. It rewrites alloc
/slot
calls into their more verbose siblings malloc
/mslot
that make the size of the alloc'ed type explicit: This is alloc2malloc.h
:
The actual rewrite
simply inspects the current def
. If this happens to be a alloc
/slot
, it will simply return the more explicit counterpart. This is alloc2malloc.cpp
:
A fixed-point pass allows you to implement a data-flow analysis. Traditionally, an optimizations performs
A fixed-point pass, however, will directly rewrite the code. You optimistically assume that all your assumptions your pass could possibly make about the program simply hold. Now, two things might happen:
If you find a contradiction to your initial assumption, you have to
In order to write a fixed-point pass, you have to inherit from FPPass. This pass expects two template parameters. The first one must be the very class you are currently implementing (this is known as CRTP in C++). The second one has the same purpose as the template parameter for rewrite passes and will most likely be Lam.
The rewrite
works exactly as for rewrite passes. However, this time around, you are guessing that the most optimistic result will happen. If you prove yourself wrong afterwards, you will gradually ascend in a lattice until the fixed-point pass stabilizes. TODO
TODO
It is important to always construct a valid program. Otherwise, bad things might happen as soon as you toss other passes into the mix. The reason is that the very program you are constructing is the only way to communicate with the other passes without directly sharing information.
Eventually, you will need to create mutables during a fixed-point pass. You must be super cautious to remember in which exact context you created said mutable. If you ever come into the same situation again (due to backtracking) you have to make sure that you return the very same mutable. Otherwise, if you create a different mutable, the PassMan will most likely diverge as it will constantly backtrack while creating new mutables that the other passes don't know anything about.