Add generator README.md
This commit is contained in:
parent
51e85f6cf8
commit
a91922e749
|
@ -0,0 +1,86 @@
|
|||
# generator
|
||||
|
||||
# Responsibilities
|
||||
|
||||
Given a compilation target, turn a well-formed FSPL semantic tree into an LLVM
|
||||
IR module tree.
|
||||
|
||||
## Organization
|
||||
|
||||
Generator defines the Target type, which contains information about the system
|
||||
that the program is being compiled for. The [native sub-package](native) uses
|
||||
Go's conditional compilation directives to provide a default Target that matches
|
||||
the system the compiler has been natively built for.
|
||||
|
||||
The entry point for all logic defined in this package is Target.Generate(). This
|
||||
method creates a new generator, and uses it to recursively generate and return an
|
||||
LLVM module. The details of the generator are hidden from other packages, and
|
||||
instances of it only last for the duration of Target.Generate().
|
||||
|
||||
The generator contains a stack of blockManagers, which plays a similar role to
|
||||
[analyzer](../analyzer).scopeContextManager, except that the stack of
|
||||
blockManagers is managed directly by the generator, which contains appropriate
|
||||
methods for pushing/popping them.
|
||||
|
||||
Like the analyzer, the generator greedily generates code, and one function may
|
||||
be generated in the middle of the generation process of another function. Thus,
|
||||
each blockManager is tied to a specific LLVM function, and is in charge of
|
||||
variables/stack allocations and to a degree, control flow flattening
|
||||
(specifically loops). It also embeds the current active block, allowing for
|
||||
generator routines to call its methods to add new instructions to the current
|
||||
block, and switch between different blocks when necessary.
|
||||
|
||||
## Operation
|
||||
|
||||
When Target.Generate() is called, a new generator is created. It is given the
|
||||
semantic tree to generate, as well as a copy of the Target. All data structure
|
||||
initialization within the generator happens at this point.
|
||||
|
||||
Then, the generate() method on the newly created generator is called. This is
|
||||
the entry point for the actual generation logic. This routine is comprised of
|
||||
two phases:
|
||||
|
||||
- Function generation
|
||||
- Method generation
|
||||
|
||||
You'll notice that there is no step for type generation. This is because types
|
||||
are generated on-demand in order to reduce IR clutter.
|
||||
|
||||
## Expression Generation
|
||||
|
||||
Since expressions make up the bulk of FSPL, expression generation makes up the
|
||||
bulk of the code generator. The generator is able to produce expressions in one
|
||||
of three modes:
|
||||
|
||||
- Location: The generator will return an IR register that contains a pointer to
|
||||
the result of the expression.
|
||||
- Value: The generator will return an IR register that directly contains the
|
||||
result of the expression.
|
||||
- Any: The generator will decide which of these two options is best for the
|
||||
specific expression, and will let the caller know which was chosen, in case it
|
||||
cares. Some expressions are better suited to returning a pointer, such as
|
||||
array subscripting or member access. Other expressions are better suited to
|
||||
returning a value, such as arithmetic operators and function calls.
|
||||
|
||||
It is important to note that generating a Value expression may return a pointer,
|
||||
because *FSPL pointers are first-class values*. The distinction between location
|
||||
and value generation modes is purely to do with LLVM. It is similar to the
|
||||
concept of location expressions within the analyzer, but not 100% identical all
|
||||
of the time.
|
||||
|
||||
Whenever an expression needs to be generated, one of the following routines is
|
||||
called:
|
||||
|
||||
- generator.generateExpression()
|
||||
- generator.generateAny()
|
||||
- generator.generateVal()
|
||||
- generator.generateLoc()
|
||||
|
||||
The generator.generateExpression() routine takes in a mode value and depending
|
||||
on it, calls one of the other more specific routines. Each of these routines, in
|
||||
turn, calls a more specialized generation routine depending on the specific
|
||||
expression.
|
||||
|
||||
If it is specifically requested to generate a value for an expression with only
|
||||
its location component defined or vice versa, generator.generateVal/Loc() will
|
||||
automatically do the conversion.
|
Loading…
Reference in New Issue