If you were constructing a compiler, what optimization at the AST level would be the nicest to have?
An optimisation that is easiest to do on the AST (rather than, say, the CFG) is tail-call optimisation: if you see a subtree of the form:
RETURN
CALL f
ARGS x, y, ...
You can replace it with a jump to f
. If f(a, b)
is the function that the tail-call appears in, the replacement is as simple as:
a = x; b = y
JUMP to root of tree
I find it easiest to represent that jump as a special "restart" statement, which the AST->CFG translation treats as an edge back to the first node. Jumping to other functions is a bit trickier since you can't just set local variables, you need to actually think ahead how arguments are passed to them and prepare to translate this at a lower level. For example, the AST might need a special node that can instruct a later pass to overwrite the current stack frame with the arguments and jump accordingly.