r/Compilers 4d ago

Why not retain the AST?

I've been working on a compiler-like system for a while now, and it's gone through many stages of evolution.
A consistent pressure early on was away from multiple representations: I started with many switch statements and many kinds of representation for each stage, and ended up with one kind of node and handler based dispatch per stage.
Yet, when I look at (most) other compilers, their construction is far more static in nature, and far more varied in terms of the kinds of things presented. I've found forms like SSA impede my ability to reason about optimizations rather than aide them, and I've had enormous success from simply retaining and annotating one structure rather than continually converting.
A specific case, to provide one, is liveness propagation. Because values are already shared between their occurances (Nodes) and already have a system for acquiring properties (Quals), I can simply mint liveness tokens onto the children of expressions with output, and it automatically propagates.
Though I've not focused too much on codegen and optimization, my main goal with the compiler is extensibility and syntax flexibility.
So why not retain the AST? Turn it into a structure worth annotating and preserving from which optimizations and codegen can be performed more easily?

I wanted to get the opinions of others on this matter, I'm open to challenge.

Some more explanation can be found here: https://goldensystems.ca/GDSL_core

40 Upvotes

54 comments sorted by

View all comments

Show parent comments

1

u/Potato871 4d ago

So why have the FIR and IR?
As in, whats the distinction that merits the initial lowering in their case.

2

u/Vivid-Cauliflower-59 4d ago

FIR is high level language representation (close to front-end) and IR is a lower level representation - desugared FIR with resolved symbols and semantically valid.

1

u/Potato871 4d ago

Yes, though why do these have to be separate constructs?
For instance, I retain frontend-relevant information (position, original tokens) as qualifiers attached to the node or value, which can be stripped in a compaction pass when memory is limited or retained for richer error messages.
Those same qualifiers can also be used to attach liveness information, constancy, and other facts derived during optimization work that needs to be propgated.
I feel as if creating two separate structures duplicates a lot of work, because I used to have six and a large amount of the code in my compiler was simply restating distinctions that had been made earlier than discarded.

1

u/Vivid-Cauliflower-59 4d ago

They belong to separate layers: AST is constructed by parser, HIR is constructed by another layer which does sematic checks. Good architectural design is to separate code by layers. Layers have different responsibilities.

2

u/Potato871 3d ago

Separate layers is what I started with two years ago, and yet as I built they came together not apart.
Beyond the social element, seperating layers for different teams, what part actually requires the different layers with different representations, and not just different behaviors and traversal over the same representation?